YBTOJ洛谷P2042:维护数列(平衡树)
生活随笔
收集整理的這篇文章主要介紹了
YBTOJ洛谷P2042:维护数列(平衡树)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 題目描述
- 解析
- 刪除區間
- 插入數列
- 修改&翻轉
- 區間和&最大子段和
- 代碼
傳送門
題目描述
解析
陰間題…
這不是裸的板子嗎?
國賽真的有人能把這題寫出來嗎…
應該算一道練習作用很強的題了
寫完這題,各種平衡樹維護區間操作的方法可以說是畢業了吧
題解封裝一個split函數的實現技巧值得借鑒
總的來說就一句:不要忘記pushdown和pushup!
刪除區間
設刪除區間為[l,r]
先把l-1結點splay到根
再把r+1轉到l-1的下面
這樣[l,r]一定就在r+1的右兒子了
直接刪掉即可
插入數列
先在外面用類似線段樹的方法建一棵完全平衡的平衡樹,然后當單點接到需要的位置(尋找位置與刪除類似)
修改&翻轉
上標記!
把對應區間轉出來,打一個標記即可
區間和&最大子段和
區間和比較無腦
最大子段和做一個經典的小白逛公園就行了
說起來很輕松,本題代碼實現在傳標記時還是很惡心的
總結一些易錯的問題:
都是辛酸淚…
上代碼吧
(實現已經比較簡潔了算上debug還是干到了小200行…)
代碼
#include<bits/stdc++.h> using namespace std; #define ll long long const int N=2e6+100; const int M=2e6+100; const ll mod=1ll<<31; ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();};while(isdigit(c)){x=x*10+c-'0';c=getchar();};return x*f; } int n,m,k; int fre[N],top; int val[N],siz[N],f[N],lp[N],rp[N],mx[N],sum[N],r,rev[N],tag[N],tr[N][2]; #define ls (tr[x][0]) #define rs (tr[x][1]) void pushup(int x){if(!x) return;siz[x]=siz[ls]+siz[rs]+1;sum[x]=sum[ls]+sum[rs]+val[x];if(!ls&&!rs){lp[x]=rp[x]=max(0,val[x]);mx[x]=val[x];}else if(!ls){lp[x]=max(0,val[x]+lp[rs]);rp[x]=max(rp[rs],sum[rs]+val[x]);mx[x]=max(mx[rs],val[x]+lp[rs]);}else if(!rs){rp[x]=max(0,val[x]+rp[ls]);lp[x]=max(lp[ls],sum[ls]+val[x]);mx[x]=max(mx[ls],val[x]+rp[ls]);}else{lp[x]=max(lp[ls],sum[ls]+val[x]+lp[rs]);rp[x]=max(rp[rs],sum[rs]+val[x]+rp[ls]);mx[x]=max(rp[ls]+val[x]+lp[rs],max(mx[ls],mx[rs]));} } void rrr(int x){rev[x]^=1;swap(ls,rs);swap(lp[x],rp[x]); } void pushdown(int x){if(tag[x]){tag[x]=rev[x]=0;if(ls){val[ls]=val[x];tag[ls]=1;sum[ls]=siz[ls]*val[x];}if(rs){val[rs]=val[x];tag[rs]=1;sum[rs]=siz[rs]*val[x]; }if(val[x]>=0){if(ls) mx[ls]=lp[ls]=rp[ls]=sum[ls];if(rs) mx[rs]=lp[rs]=rp[rs]=sum[rs];}else{if(ls){lp[ls]=rp[ls]=0;mx[ls]=sum[ls];}if(rs){lp[rs]=rp[rs]=0;mx[rs]=sum[rs];}}}if(rev[x]){rev[x]=0;if(ls) rrr(ls);if(rs) rrr(rs);} } void dfs1(int x){if(!x) return;pushdown(x);dfs1(ls);printf("%d ",val[x]);dfs1(rs);pushup(x); } void dfs2(int x){if(!x) return;pushdown(x);printf("x=%d val=%d ls=%d rs=%d siz=%d\n",x,val[x],ls,rs,siz[x]);dfs2(ls);dfs2(rs);pushup(x); } void debug(int f){printf("------r=%d\n",r);if(f==1) dfs1(r);else dfs2(r);printf("\n\n"); } int New(int v,int fa){int x=fre[top--];val[x]=mx[x]=sum[x]=v;lp[x]=rp[x]=max(0,v);f[x]=fa;siz[x]=1;tag[x]=rev[x]=0;return x; } #define which(x) (tr[f[x]][1]==x) void rotate(int x){int fa=f[x],gfa=f[fa];pushdown(gfa);pushdown(fa);pushdown(x);int k=which(x),son=tr[x][k^1];f[x]=gfa;if(gfa) tr[gfa][which(fa)]=x;f[fa]=x;tr[x][k^1]=fa;f[son]=fa;tr[fa][k]=son;pushup(fa);pushup(x);pushup(gfa); } void splay(int x,int goal){if(x==goal) return;for(int fa;(fa=f[x])!=goal;rotate(x)){if(f[fa]!=goal)which(x)==which(fa)?rotate(fa):rotate(x);}if(!goal) r=x; } int a[N]; int build(int l,int r,int fa){if(l>r) return 0;int mid=(l+r)>>1;int x=New(a[mid],fa);tr[x][0]=build(l,mid-1,x);tr[x][1]=build(mid+1,r,x);pushup(x); // printf("l=%d r=%d x=%d pl=%d siz=%d\n",l,r,x,mid,siz[x]);return x; } int find(int x,int k){pushdown(x);if(siz[ls]>=k) return find(ls,k);else if(siz[ls]+1==k) return x;else return find(rs,k-siz[ls]-1); } int split(int l,int rr){int a=find(r,l-1);splay(a,0);int b=find(r,rr+1);splay(b,a);return tr[b][0]; } void add(int x,int k,int s){pushdown(x);tr[x][k]=s;f[s]=x;pushup(x); } char s[150]; void ins(){int pos=read(),tot=read();pos++;for(int i=1;i<=tot;i++) a[i]=read();int now=build(1,tot,0);if(pos==1){int x=find(r,1);splay(x,0);int y=find(r,2);splay(y,x);add(y,0,now);splay(y,0);return;}int x=split(pos,pos);add(x,1,now);pushup(x);splay(now,0); } void save(int x){if(!x) return;fre[++top]=x;save(ls);save(rs); } void del(){int pos=read(),tot=read();pos++;int x=split(pos,pos+tot-1),fa=f[x];save(x);tr[fa][0]=0;pushup(fa);splay(fa,0); } void same(){int pos=read(),tot=read(),v=read();pos++;int x=split(pos,pos+tot-1);val[x]=v;tag[x]=1;sum[x]=siz[x]*v;lp[x]=rp[x]=max(0,sum[x]);splay(x,0); } void reverse(){int pos=read(),tot=read();pos++;int x=split(pos,pos+tot-1);rrr(x);//printf("x=%d\n",x);debug(2);splay(x,0); } void getsum(){int pos=read(),tot=read();pos++;int x=split(pos,pos+tot-1);printf("%d\n",sum[x]); } void maxsum(){printf("%d\n",mx[r]); } int main(){for(int i=500050;i>=1;i--) fre[++top]=i;n=read();m=read();for(int i=1;i<=n;i++) a[i]=read();r=build(1,n,0);splay(find(r,1),0);add(r,0,New(-20000,r));splay(find(r,n+1),0);add(r,1,New(-20000,r));//debug(1);for(int i=1;i<=m;i++){// printf("-------------------------------------\n");scanf(" %s",s+1);if(s[1]=='I') ins();else if(s[1]=='D') del();else if(s[3]=='K') same();else if(s[1]=='R') reverse();else if(s[1]=='G') getsum();else maxsum();//debug(1);}return 0; } /* */總結
以上是生活随笔為你收集整理的YBTOJ洛谷P2042:维护数列(平衡树)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 熔火之心在哪?多少级可以进 熔火之心是什
- 下一篇: 9.25 模拟