HDU 5919 Sequence II 主席树
題目鏈接:
http://acm.hdu.edu.cn/showproblem.php?pid=5919
Sequence II
Time Limit: 9000/4500 MS (Java/Others)Memory Limit: 131072/131072 K (Java/Others)
問題描述
Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,?,an There are m queries.
In the i-th query, you are given two integers li and ri. Consider the subsequence ali,ali+1,ali+2,?,ari.
We can denote the positions(the positions according to the original sequence) where an integer appears first in this subsequence as p(i)1,p(i)2,?,p(i)ki (in ascending order, i.e.,p(i)1<p(i)2<?<p(i)ki).
Note that ki is the number of different integers in this subsequence. You should output p(i)?ki2?for the i-th query.
輸入
In the first line of input, there is an integer T (T≤2) denoting the number of test cases.
Each test case starts with two integers n (n≤2×105) and m (m≤2×105). There are n integers in the next line, which indicate the integers in the sequence(i.e., a1,a2,?,an,0≤ai≤2×105).
There are two integers li and ri in the following m lines.
However, Mr. Frog thought that this problem was too young too simple so he became angry. He modified each query to l‘i,r‘i(1≤l‘i≤n,1≤r‘i≤n). As a result, the problem became more exciting.
We can denote the answers as ans1,ans2,?,ansm. Note that for each test case ans0=0.
You can get the correct input li,ri from what you read (we denote them as l‘i,r‘i)by the following formula:
li=min{(l‘i+ansi?1) mod n+1,(r‘i+ansi?1) mod n+1}
ri=max{(l‘i+ansi?1) mod n+1,(r‘i+ansi?1) mod n+1}
輸出
You should output one single line for each test case.
For each test case, output one line “Case #x: p1,p2,?,pm”, where x is the case number (starting from 1) and p1,p2,?,pm is the answer.
樣例輸入
2
5 2
3 3 1 5 4
2 2
4 4
5 2
2 5 2 1 2
2 3
2 4
樣例輸出
Case #1: 3 3
Case #2: 3 1
題意
求區間[l,r]的所有不重復的數(重復的以第一次出現的位置為準)位于中間(位置在中間,不是值)那個數所在的位置。
題目強制在線
題解
用主席樹,倒過來建樹,從第n個位置建到第1個位置,對于重復的數邊做邊刪,保證只留在最左邊的那個,然后對于查詢[l,r],我們去查rt[l]那棵樹的l,r區間,得到不重復的數有cnt個,然后用求區間第k大的辦法去求第(cnt+1)/2大的數。
還有一種思路,每個數存它前驅的位置,然后用主席樹求區間[l,r]中比l小的數的個數,從而可以求區間[l,r]內不同的數的個數,然后二分t,去找中間的位置, 這樣的復雜度是nlogn+q*logn*logn,會卡時間,反正我是t了。
代碼
#include<map> #include<set> #include<cmath> #include<queue> #include<stack> #include<ctime> #include<vector> #include<cstdio> #include<string> #include<bitset> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #include<functional> #include<sstream> using namespace std; #define X first #define Y second #define mkp make_pair #define mid (l+(r-l)/2) #define lson(o) (tre[(o)].ls) #define rson(o) (tre[(o)].rs) #define sumv(o) (tre[(o)].sum) #define sz() size() #define pb(v) push_back(v) #define all(o) (o).begin(),(o).end() #define clr(a,v) memset(a,v,sizeof(a)) #define bug(a) cout<<#a<<" = "<<a<<endl #define rep(i,a,b) for(int i=a;i<(b);i++) #define scf scanf #define prf printftypedef long long LL; typedef vector<int> VI; typedef pair<int,int> PII; typedef vector<pair<int,int> > VPII;const int INF=0x3f3f3f3f; const LL INFL=0x3f3f3f3f3f3f3f3fLL; const double eps=1e-8; const double PI = acos(-1.0);//start----------------------------------------------------------------------const int maxn=201010;///nlogn空間復雜度 ///注意:由于有增加和刪除兩個操作!所以空間是2n*log(2n) struct Tre {int ls,rs,sum;Tre() {ls=rs=sum=0;} } tre[maxn*50];int n,m; int rt[maxn],tot;int _v,_p; void update(int &o,int l,int r) {tre[++tot]=tre[o],o=tot;if(l==r) {sumv(o)+=_v;} else {if(_p<=mid) update(lson(o),l,mid);else update(rson(o),mid+1,r);sumv(o)=sumv(lson(o))+sumv(rson(o));} }///區間內不同的數有幾個 int _res,ql,qr; void query(int o,int l,int r) {if(ql<=l&&r<=qr) {_res+=sumv(o);} else {if(ql<=mid) query(lson(o),l,mid);if(qr>mid) query(rson(o),mid+1,r);} }///區間第k大 int _res2; void query2(int o,int l,int r,int k) {if(l==r) {_res2=l;} else {if(k<=sumv(lson(o))) query2(lson(o),l,mid,k);else query2(rson(o),mid+1,r,k-sumv(lson(o)));} }int arr[maxn],mp[maxn];///0是個超級節點 void init() {rt[n+1]=tot=0; }int main() {int tc,kase=0;scf("%d",&tc);while(tc--) {scf("%d%d",&n,&m);init();for(int i=1; i<=n; i++) {scf("%d",&arr[i]);}///主席樹for(int i=1; i<=n; i++) mp[i]=n+1;for(int i=n; i>=1; i--) {rt[i]=rt[i+1];_v=1,_p=i;update(rt[i],1,n);if(mp[arr[i]]<=n) {_v=-1,_p=mp[arr[i]];update(rt[i],1,n);}mp[arr[i]]=i;}int ans=0;VI lis;while(m--) {int ll,rr;scf("%d%d",&ll,&rr);int t1=(ll+ans)%n+1,t2=(rr+ans)%n+1;int l=min(t1,t2),r=max(t1,t2);///求區間內不同的數有幾個ql=l,qr=r,_res=0;query(rt[l],1,n);int k=(_res+1)/2;///求區間第k大query2(rt[l],1,n,k);ans=_res2;lis.pb(ans);}prf("Case #%d:",++kase);rep(i,0,lis.sz()) {prf(" %d",lis[i]);}putchar('\n');}return 0; }//end-----------------------------------------------------------------------轉載于:https://www.cnblogs.com/fenice/p/5933231.html
總結
以上是生活随笔為你收集整理的HDU 5919 Sequence II 主席树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Struts2拦截器之FileUploa
- 下一篇: 坑爹的微信授权配置