【bzoj3489】A simple rmq problem
阿新 • • 發佈:2018-07-15
str 順序 ring n+1 namespace http names 需要 update
,所以這裏要註意主席樹的區間應該是\([1,n+1]\)
Portal -->bzoj3489
Solution
最近計劃智力康復qwq(話說這題一年前剛剛開始寫樹套樹的時候感覺好難啊qwq現在看其實還好也算是有進步的嘛!)
比較重要的一步是,要將“在\([l,r]\)中只出現一次”這個條件轉化成"\(nxt[x]>r\)&&\(pre[x]<l\)",其中\(nxt[x]\)表示下一個出現位置\(x\)的數的位置,\(pre[x]\)表示前一個
然後我們就發現其實是有三個限制:
1、\(pre[x]<l\)
2、\(nxt[x]>r\)
3、最大
那所以我們用兩棵主席樹套在一起就好了
? 外層的主席樹按照\(pre[x]\)來順序加點,樹內按照\(nxt\)的順序為關鍵字,然後對於每個節點(也就是區間啦),再開一棵主席樹,以\(nxt\)為根的順序,樹內以\(val[x]\)為關鍵字(也就是權值線段樹啦)
? 然後修改直接修改,查詢的時候我們先二分一下外層主席樹應該調用哪個\(rt\),也就是二分一個最大的\(pos\)滿足\(pre[pos]<l\),然後\(query(rt[pos],l,r)\)即可
想清楚了的話還是比較好寫的
有一些需要稍微註意一下的小細節
1、如果說對於那些後面已經沒有與其相同的數的位置,為了方便我們將其\(nxt\)賦成\(n+1\)
2、查詢的時候,要註意因為我們要求的是\(nxt[x]>r\),所以在查詢中涉及到的範圍應該是\(>\)而不是\(>=\)之類的,跟平時寫線段樹有那麽一點點小區別稍微註意一下
代碼大概長這個樣子
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=100010,M=200010,SEG=N*20; struct Data{ int pre,nxt,id,val; friend bool operator < (Data x,Data y) {return x.pre<y.pre;} }a[N]; int loc[N]; int n,m,ans; namespace NodeSeg{/*{{{*/ int ch[SEG*20][2],mx[SEG*20],rt[SEG]; int n,tot; int newnode(int pre){ ch[++tot][0]=ch[pre][0],ch[tot][1]=ch[pre][1]; mx[tot]=mx[pre]; return tot; } void pushup(int x){mx[x]=max(mx[ch[x][0]],mx[ch[x][1]]);} void _update(int pre,int &x,int lx,int rx,Data &delta){ x=newnode(pre); if (lx==rx){mx[x]=delta.val;return;} int mid=lx+rx>>1; if (delta.id<=mid) _update(ch[pre][0],ch[x][0],lx,mid,delta); else _update(ch[pre][1],ch[x][1],mid+1,rx,delta); pushup(x); } void update(int pre,int x,Data delta){_update(rt[pre],rt[x],1,n,delta);} int _query(int x,int l,int r,int lx,int rx){ if (mx[x]==0) return 0; if (l<=lx&&rx<=r) return mx[x]; int mid=lx+rx>>1,ret=0; if (l<=mid) ret=max(ret,_query(ch[x][0],l,r,lx,mid)); if (r>mid) ret=max(ret,_query(ch[x][1],l,r,mid+1,rx)); return ret; } int query(int x,int l,int r){return _query(rt[x],l,r,1,n);} }/*}}}*/ namespace NextSeg{/*{{{*/ int ch[SEG][2],rt[SEG]; int n,tot; int newnode(int pre,Data delta){ ch[++tot][0]=ch[pre][0]; ch[tot][1]=ch[pre][1]; NodeSeg::update(pre,tot,delta); return tot; } void _update(int pre,int &x,int lx,int rx,Data delta){ x=newnode(pre,delta); if (lx==rx) return; int mid=lx+rx>>1; if (delta.nxt<=mid) _update(ch[pre][0],ch[x][0],lx,mid,delta); else _update(ch[pre][1],ch[x][1],mid+1,rx,delta); } void update(int x,Data delta){_update(rt[x-1],rt[x],1,n,delta);} int _query(int x,int l,int r,int lx,int rx){ if (r<lx&&rx<=n) return NodeSeg::query(x,l,r); int mid=lx+rx>>1,ret=0; if (r<mid) ret=max(ret,_query(ch[x][0],l,r,lx,mid)); ret=max(ret,_query(ch[x][1],l,r,mid+1,rx)); return ret; } int query(int x,int l,int r){return _query(rt[x],l,r,1,n);} }/*}}}*/ int read(){ int ret=0; char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while ('0'<=ch&&ch<='9') ret=ret*10+ch-'0',ch=getchar(); return ret; } void prework(){ for (int i=1;i<=n;++i) a[i].pre=0,a[i].nxt=n+1; for (int i=1;i<=n;++i){ a[i].id=i; if (loc[a[i].val]) a[loc[a[i].val]].nxt=i,a[i].pre=loc[a[i].val]; loc[a[i].val]=i; } NodeSeg::n=n+1; NextSeg::n=n+1; } int get_pos(int x){ int l=1,r=n,mid,ret=l; while (l<=r){ mid=l+r>>1; if (x<=a[mid].pre) r=mid-1; else l=mid+1; } return l-1; } int main(){/*{{{*/ #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); #endif int x,y,x1,y1,pos; n=read(); m=read(); for (int i=1;i<=n;++i) a[i].val=read(); prework(); sort(a+1,a+1+n); for (int i=1;i<=n;++i) NextSeg::update(i,a[i]); for (int i=1;i<=m;++i){ x1=read(); y1=read(); x=min((x1+ans)%n+1,(y1+ans)%n+1); y=max((x1+ans)%n+1,(y1+ans)%n+1); pos=get_pos(x); ans=NextSeg::query(pos,x,y); printf("%d\n",ans); } }/*}}}*/
【bzoj3489】A simple rmq problem