【Luogu】P3380树套树模板(线段树套Splay)
生活随笔
收集整理的這篇文章主要介紹了
【Luogu】P3380树套树模板(线段树套Splay)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接
幸甚至哉,歌以詠志。
拿下了曾經是那么遙不可及的線段樹,學會了曾經高不可攀的平衡樹,弄懂了裝B的時候才掛在嘴邊的樹套樹。
每道模板都是鏈上的一顆珠子。把它們挨個串起來,就成為我成長的歷程。
抒情結束開始講題
這道題我們用線段樹存平衡樹的根節點。比如我們有一棵線段樹
這樣子。線段樹的一個節點 ? 存 ? 它表示的那個區間 ? 所對應的 ?平衡樹 ? 的根節點編號。這樣每個節點都擁有一棵平衡樹。是不是很炫呢?
對于操作1我們就可以把所有零散的區間里比它小的數的個數都找出來,+1就是答案啦。
對于操作2我們可以二分數,然后不斷地進行操作1.
對于操作3我們用logn的時間把所有包含這個點的區間都修改一遍。
對于操作4和操作5,不多講了。
很炫吧
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cctype> #define mid ((l+r)>>1) #define left (rt<<1) #define right (rt<<1|1) #define lson l,mid,left #define rson mid+1,r,rightusing std::max; using std::min;inline int read(){int num=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}while(isdigit(ch)){num=num*10+ch-'0';ch=getchar();}return num*f; }int s[502000]; int q[102000];struct Node{int e[2],fa,val,size,sum; }tree[5002000]; int tot,point; inline void update(int x){tree[x].size=tree[x].sum;if(tree[x].e[0]) tree[x].size+=tree[tree[x].e[0]].size;if(tree[x].e[1]) tree[x].size+=tree[tree[x].e[1]].size; } inline void connect(int x,int fa,int how){ tree[x].fa=fa; tree[fa].e[how]=x; } inline int iden(int x){ return x==tree[tree[x].fa].e[1]; } void rotate(int x,int rt){int y=tree[x].fa; int r=tree[y].fa;if(y==s[rt]) s[rt]=x;int sony=iden(x); int sonr=iden(y);int b=tree[x].e[sony^1];connect(b,y,sony);connect(y,x,sony^1);connect(x,r,sonr);update(y); update(x); }void splay(int pos,int to,int rt){to=tree[to].fa;while(tree[pos].fa!=to){if(tree[tree[pos].fa].fa==to) rotate(pos,rt);elseif(iden(pos)==iden(tree[pos].fa)){ rotate(tree[pos].fa,rt); rotate(pos,rt); }else { rotate(pos,rt); rotate(pos,rt); }} }inline int create(int val,int fa){tree[++tot].val=val;tree[tot].fa=fa;tree[tot].sum=tree[tot].size=1;return tot; }inline void Delete(int x){tree[x].e[0]=tree[x].e[1]=0;if(x==tot) tot--; }int build(int val,int rt){point++;if(!s[rt]){ s[rt]=create(val,0); return s[rt];}else{int now=s[rt];while(1){tree[now].size++;if(val==tree[now].val){ tree[now].sum++; return now; }int nxt=val<tree[now].val?0:1;if(!tree[now].e[nxt]){create(val,now);tree[now].e[nxt]=tot;return tot;}now=tree[now].e[nxt];}}return 0; }inline void insert(int val,int rt){int p=build(val,rt);splay(p,s[rt],rt); }int find(int val,int rt){int now=s[rt];while(now){if(tree[now].val==val){ splay(now,s[rt],rt); return now; }int nxt=val>tree[now].val;if(!tree[now].e[nxt]) return 0;now=tree[now].e[nxt];} }void pop(int val,int rt){int deal=find(val,rt);if(!deal) return;point--;if(tree[deal].sum>1){ tree[deal].sum--; tree[deal].size--; return; }if(!tree[deal].e[0]){ s[rt]=tree[deal].e[1]; tree[s[rt]].fa=0; }else{int le=tree[deal].e[0];while(tree[le].e[1]) le=tree[le].e[1];splay(le,tree[deal].e[0],rt);int ri=tree[deal].e[1];connect(ri,le,1); s[rt]=le;update(le);}Delete(deal); }int rank(int val,int rt){int ans=0,now=s[rt];while(1){//printf("%d %d\n",now,tree[now].sum);if(val<tree[now].val){now=tree[now].e[0];if(!now) return ans;}else{if(tree[now].e[0]) ans+=tree[tree[now].e[0]].size;if(val==tree[now].val||!tree[now].e[1]){if(val>tree[now].val) ans+=tree[now].sum;splay(now,s[rt],rt);return ans;}ans+=tree[now].sum; now=tree[now].e[1];}} }inline int lower(int val,int rt){int ans=-2147483647,now=s[rt];while(1){if(!now) return ans;if(tree[now].val<val&&tree[now].val>ans) ans=tree[now].val;int nxt=val>tree[now].val?1:0;now=tree[now].e[nxt];} }inline int upper(int val,int rt){int ans=2147483647,now=s[rt];while(1){if(!now) return ans;if(tree[now].val>val&&tree[now].val<ans) ans=tree[now].val;int nxt=val>tree[now].val?1:0;now=tree[now].e[nxt];} }int lows(int val,int rt){int ans=-2147483647,now=s[rt];while(1){if(!now) return ans;if(tree[now].val<=val&&tree[now].val>ans) ans=tree[now].val;if(tree[now].val==val) return ans;int nxt=val>tree[now].val?1:0;now=tree[now].e[nxt];} }void Build(int l,int r,int rt){if(l>r) return;if(l==r){insert(q[l],rt);return;}Build(lson);Build(rson);for(int i=l;i<=r;++i) insert(q[i],rt);return; }int findrank(int from,int to,int num,int l,int r,int rt){if(from<=l&&to>=r) return rank(num,rt);int ans=0;if(from<=mid) ans+=findrank(from,to,num,lson);if(to>mid) ans+=findrank(from,to,num,rson);return ans; }void Update(int o,int num,int l,int r,int rt){pop(q[o],rt);insert(num,rt);if(l==r) return;if(o<=mid) Update(o,num,lson);else Update(o,num,rson); }int findlower(int from,int to,int num,int l,int r,int rt){if(from<=l&&to>=r) return lower(num,rt);int ans=-2147483647;if(from<=mid) ans=max(ans,findlower(from,to,num,lson));if(to>mid) ans=max(ans,findlower(from,to,num,rson));return ans; }int findupper(int from,int to,int num,int l,int r,int rt){if(from<=l&&to>=r) return upper(num,rt);int ans=2147483647;if(from<=mid) ans=min(ans,findupper(from,to,num,lson));if(to>mid) ans=min(ans,findupper(from,to,num,rson));return ans; }int main(){int n=read(),m=read();for(int i=1;i<=n;++i) q[i]=read();Build(1,n,1);for(register int i=1;i<=m;++i){int opt=read();if(opt==1){int l=read(),r=read(),q=read();printf("%d\n",findrank(l,r,q,1,n,1)+1);}else if(opt==2){int l=read(),r=read(),q=read();int a=0,b=1e8,Ans=0;while(a<=b){int m=(a+b)>>1;int x=lows(m,1);if(findrank(l,r,x,1,n,1)+1>q) b=m-1;else{a=m+1;Ans=x;}}printf("%d\n",Ans);}else if(opt==3){int l=read(),r=read();Update(l,r,1,n,1);q[l]=r;}else if(opt==4){int l=read(),r=read(),q=read();printf("%d\n",findlower(l,r,q,1,n,1));}else if(opt==5){int l=read(),r=read(),q=read();printf("%d\n",findupper(l,r,q,1,n,1));}}return 0; }?
轉載于:https://www.cnblogs.com/cellular-automaton/p/8041493.html
總結
以上是生活随笔為你收集整理的【Luogu】P3380树套树模板(线段树套Splay)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: bzoj1051 [HAOI2006]受
- 下一篇: Oracle多行函数