BZOJ3489 A simple rmq problem 【可持久化树套树】*
BZOJ3489 A simple rmq problem
Description
因為是OJ上的題,就簡單點好了。給出一個長度為n的序列,給出M個詢問:在[l,r]之間找到一個在這個區間里只出現過一次的數,并且要求找的這個數盡可能大。如果找不到這樣的數,則直接輸出0。我會采取一些措施強制在線。
Input
第一行為兩個整數N,M。M是詢問數,N是序列的長度(N<=100000,M<=200000)
第二行為N個整數,描述這個序列{ai},其中所有1<=ai<=N
再下面M行,每行兩個整數x,y,
詢問區間[l,r]由下列規則產生(OIER都知道是怎樣的吧>_<):
l=min((x+lastans)mod n+1,(y+lastans)mod n+1);
r=max((x+lastans)mod n+1,(y+lastans)mod n+1);
Lastans表示上一個詢問的答案,一開始lastans為0
Output
一共M行,每行給出每個詢問的答案。
Sample Input
10 10
6 4 9 10 9 10 9 4 10 4
3 8
10 1
3 4
9 4
8 1
7 8
2 9
1 1
7 3
9 9
Sample Output
4
10
10
0
0
10
0
4
0
4
還是吐槽一下BZOJ的土豆(評測機),什么數組開小了顯示WA,數組開大一點就CE,這可真是友好,請問RE呢?MLE呢?????????
然后講講這題思路
一開始看到以為是樹套樹套樹
蒙圈了
想了⑩分鐘無果然后就去看題解
結果發現可以用排序的方法把三維降成兩維
只不過嘛。需要可持久化
不過我們不虛
可持久化樹套樹不就是在可持久化線段樹上多加一句插入嗎理直氣壯
首先我們考慮一個數在區間內出現一次的充要條件是什么
1.l<=posi<=r1.l<=posi<=r
2.l>prei2.l>prei
3.r<nxti3.r<nxti
其中pos表示位置,pre和nxt分別表示上一個和下一個這個數出現的位置
很妙啊
我們考慮以pre為鍵值排序
然后我們發現我們查詢的區間變成了一個前綴
所以就將pre可持久化一下
然后我們又發現nxt也是我們的限制條件
所以我們在外層的樹上以nxt為下標,所以查詢就變成了在線段樹上查詢后綴
但是還有pos的限制怎么辦?
所以就把內層樹搞成原序列的位置就好了
然后查詢的時候非常套路地二分一下pre的位置,剩下的該怎么查怎么查
#include<bits/stdc++.h> using namespace std; inline int read(){int ans=0,w=1;char c=getchar();while(!isdigit(c)&&c!='-')c=getchar();if(c=='-')w=-1,c=getchar();while(isdigit(c))ans=(ans<<1)+(ans<<3)+c-'0',c=getchar();return ans*w; } #define N 100010 int n,m,lastans=0; struct Node{int val,pos,pre,nxt;}p[N]; bool cmp(Node a,Node b){return a.pre<b.pre;} //inside 原序列順序 int ld[N*350],rd[N*350],maxv[N*350]; int cnt=0; void insert(int &t,int last,int l,int r,int pos,int vl){t=++cnt;maxv[t]=max(vl,maxv[last]);if(l==r)return;ld[t]=ld[last];rd[t]=rd[last];int mid=(l+r)>>1;if(pos<=mid)insert(ld[t],ld[last],l,mid,pos,vl);else insert(rd[t],rd[last],mid+1,r,pos,vl); } int query(int t,int l,int r,int L,int R){if(!t)return 0;if(L<=l&&r<=R)return maxv[t];int mid=(l+r)>>1;if(R<=mid)return query(ld[t],l,mid,L,R);if(L>mid)return query(rd[t],mid+1,r,L,R);return max(query(ld[t],l,mid,L,R),query(rd[t],mid+1,r,L,R)); } //outside nxt順序 int rt[N*20],lc[N*20],rc[N*20],tot=0; void insert(int &t,int last,int l,int r,int key,int pos,int vl){t=++tot;insert(rt[t],rt[last],1,n,pos,vl);if(l==r)return;lc[t]=lc[last];rc[t]=rc[last];int mid=(l+r)>>1;if(key<=mid)insert(lc[t],lc[last],l,mid,key,pos,vl);else insert(rc[t],rc[last],mid+1,r,key,pos,vl); } int query(int t,int l,int r,int L,int R,int ql,int qr){if(!t)return 0;if(L<=l&&r<=R)return query(rt[t],1,n,ql,qr);int mid=(l+r)>>1;if(R<=mid)return query(lc[t],l,mid,L,R,ql,qr);if(L>mid)return query(rc[t],mid+1,r,L,R,ql,qr);return max(query(lc[t],l,mid,L,R,ql,qr),query(rc[t],mid+1,r,L,R,ql,qr)); } int outrt[N]; int pre[N],nxt[N]; int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)p[i].pos=i,scanf("%d",&p[i].val);for(int i=1;i<=n;i++)pre[i]=0,nxt[i]=n+1;for(int i=1;i<=n;i++)p[i].pre=pre[p[i].val],pre[p[i].val]=i;for(int i=n;i>=1;i--)p[i].nxt=nxt[p[i].val],nxt[p[i].val]=i;//for(int i=1;i<=1000;i++)cout<<i<<" "<<p[i].pre<<" "<<p[i].nxt<<endl;sort(p+1,p+n+1,cmp);for(int i=1;i<=n;i++)//持久化pre的順序insert(outrt[i],outrt[i-1],1,n+1,p[i].nxt,p[i].pos,p[i].val);for(int i=1;i<=m;i++){int l,r;scanf("%d%d",&l,&r);l=(l+lastans)%n+1;r=(r+lastans)%n+1;if(l>r)swap(l,r);int ql=1,qr=n,tmp=0;while(ql<=qr){int mid=(ql+qr)>>1;if(p[mid].pre<l)ql=mid+1,tmp=mid;else qr=mid-1;}printf("%d\n",lastans=query(outrt[tmp],1,n+1,r+1,n+1,l,r));}return 0; }
轉載于:https://www.cnblogs.com/dream-maker-yk/p/9676288.html
總結
以上是生活随笔為你收集整理的BZOJ3489 A simple rmq problem 【可持久化树套树】*的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [js] 渲染树构建、布局及绘制
- 下一篇: 小程序之脚本语言