【bzoj3786】【星系探索】【dfs序+splay】
阿新 • • 發佈:2019-01-24
n<=100000,m<=300000,1<di,xi<=n,wi,qi<=100000.保證操作合法。
題解:
用splay維護樹的括號序列.
l[x],r[x]分別表示點x的進棧位置和出棧位置.
把左括號的位置賦成正值,右括號的位置賦成負值.
那查詢根到x的鏈和就是[l[1],l[x]]的和.
修改x所在子樹就是修改[l[x],r[x]]這一段序列.
子樹移動就是找到這棵子樹代表的這段序列,然後插到一個點後面.
這些都可以用splay來處理.
程式碼:
#include<iostream> #include<cstdio> #include<cstring> #define N 200010 #define LL long long using namespace std; int point[N],n,m,x,y,next[N<<1],a[N],cnt,top=1,l[N],r[N]; int st[N],root; char ch; struct use{ int st,en; }e[N<<1]; struct node{ int g,v,fa,lg,rg,c[2]; LL s,ad; }t[N]; inline void ins(int x,int y){ next[++cnt]=point[x];point[x]=cnt; e[cnt].st=x;e[cnt].en=y; } inline int read(){ int x(0);char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } void dfs(int x,int fa){ l[x]=++top;t[top].g=1;t[top].v=a[x]; for (int i=point[x];i;i=next[i]) if (e[i].en!=fa) dfs(e[i].en,x); r[x]=++top;t[top].g=2;t[top].v=-a[x]; } inline void update(int k){ int a=t[k].c[0],b=t[k].c[1]; t[k].s=t[a].s+t[b].s+(LL)t[k].v; t[k].lg=t[a].lg+t[b].lg+(t[k].g==1); t[k].rg=t[a].rg+t[b].rg+(t[k].g==2); } void build(int k,int l,int r){ if (l>r) return; int mid=(l+r)>>1; if (k) t[k].c[mid>k]=mid; t[mid].fa=k; build(mid,l,mid-1); build(mid,mid+1,r); update(mid); } inline void paint(int x,int c){ if (t[x].g==1) t[x].v+=c; if (t[x].g==2) t[x].v-=c; t[x].s+=(LL)(t[x].lg-t[x].rg)*c; t[x].ad+=c; } inline void pushdown(int x){ int a=t[x].c[0],b=t[x].c[1]; if (t[x].ad){ if (a) paint(a,t[x].ad); if (b) paint(b,t[x].ad); } t[x].ad=0; } inline void rotate(int x,int &k){ int y=t[x].fa,z=t[y].fa,a,b; if (t[y].c[0]==x) a=0;else a=1;b=a^1; if (y==k) k=x; else{ if (t[z].c[0]==y) t[z].c[0]=x; else t[z].c[1]=x; } t[x].fa=z;t[y].fa=x;t[t[x].c[b]].fa=y; t[y].c[a]=t[x].c[b];t[x].c[b]=y; update(y);update(x); } inline void splay(int x,int &k){ int top(0); st[++top]=x; for (int i=x;t[i].fa;i=t[i].fa) st[++top]=t[i].fa; while(top--) pushdown(st[top]); while (x!=k){ int y=t[x].fa,z=t[y].fa; if (y!=k){ if ((t[y].c[0]==x)^(t[z].c[0]==y)) rotate(x,k); else rotate(y,k); } rotate(x,k); } } inline int left(int x){ while (t[x].c[1]) x=t[x].c[1]; return x; } inline int right(int x){ while (t[x].c[0]) x=t[x].c[0]; return x; } inline int split(int x,int y){ int a,b; splay(x,root);a=left(t[x].c[0]); splay(y,root);b=right(t[y].c[1]); splay(a,root);splay(b,t[a].c[1]); return t[b].c[0]; } inline void query(int k){ int x=split(l[1],l[k]); printf("%lld\n",t[x].s); } inline void add(int k,int y){ int x=split(l[k],r[k]); paint(x,y); } inline void change(int u,int v){ int a,b,x=split(l[u],r[u]); a=root;b=t[a].c[1];t[b].c[0]=0; update(b);update(a); a=l[v];splay(a,root); b=right(t[a].c[1]); splay(b,t[a].c[1]); t[b].c[0]=x;t[x].fa=b; update(b);update(a); } int main(){ // freopen("a.in","r",stdin); //freopen("a.out","w",stdout); n=read(); for (int i=2;i<=n;i++){ x=read();ins(x,i);ins(i,x); } for (int i=1;i<=n;i++) a[i]=read(); dfs(1,0); top++;root=(1+top)>>1; build(0,1,top); //for (int i=1;i<=top;i++) cout<<c[i][0]<<' '<<c[i][1]<<endl; m=read(); for (int i=1;i<=m;i++){ for(ch=getchar();ch<'A'||ch>'Z';ch=getchar()); if (ch=='Q'){ x=read(); query(x); } if (ch=='F'){ x=read();y=read(); add(x,y); } if (ch=='C'){ x=read();y=read(); change(x,y); } } }