【传送门:BZOJ2843】
简要题意:
给出n个点以及它们的权值,有m个操作,4种操作:
1.询问从x到y的路径上的权值和,如果不连通则输出impossible
2.连接x和y,如果本来就联通则输出no,否则输出yes
3.修改第x个点的权值,改为c
题解:
LCT,只要在每个点保存它子树的权值和就行了
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; struct node { int f,son[2],c,sum; bool fz; node() { fz=false; son[0]=son[1]=0; f=c=sum=0; } }tr[310000]; void update(int x) { int lc=tr[x].son[0],rc=tr[x].son[1]; tr[x].sum=tr[lc].sum+tr[rc].sum+tr[x].c; } void reverse(int x) { tr[x].fz=false; swap(tr[x].son[0],tr[x].son[1]); int lc=tr[x].son[0],rc=tr[x].son[1]; tr[lc].fz=1-tr[lc].fz; tr[rc].fz=1-tr[rc].fz; } void rotate(int x,int w) { int f=tr[x].f,ff=tr[f].f; int r,R; r=tr[x].son[w];R=f; tr[R].son[1-w]=r; if(r!=0) tr[r].f=R; r=x;R=ff; if(tr[R].son[0]==f) tr[R].son[0]=r; else if(tr[R].son[1]==f) tr[R].son[1]=r; tr[r].f=R; r=f;R=x; tr[R].son[w]=r; tr[r].f=R; update(f);update(x); } int tmp[310000]; void splay(int x,int rt) { int i=x,s=0; while(tr[i].f!=0&&(tr[tr[i].f].son[0]==i||tr[tr[i].f].son[1]==i)) { tmp[++s]=i; i=tr[i].f; } tmp[++s]=i; while(s!=0) { i=tmp[s--]; if(tr[i].fz==true) reverse(i); } while(tr[x].f!=rt&&(tr[tr[x].f].son[0]==x||tr[tr[x].f].son[1]==x)) { int f=tr[x].f,ff=tr[f].f; if(ff==rt||(tr[ff].son[0]!=f&&tr[ff].son[1]!=f)) { if(tr[f].son[0]==x) rotate(x,1); else if(tr[f].son[1]==x) rotate(x,0); } else { if(tr[f].son[0]==x&&tr[ff].son[0]==f){rotate(f,1);rotate(x,1);continue;} if(tr[f].son[0]==x&&tr[ff].son[1]==f){rotate(x,1);rotate(x,0);continue;} if(tr[f].son[1]==x&&tr[ff].son[0]==f){rotate(x,0);rotate(x,1);continue;} if(tr[f].son[1]==x&&tr[ff].son[1]==f){rotate(f,0);rotate(x,0);continue;} } } } void access(int x) { int y=0; while(x!=0) { splay(x,0); tr[x].son[1]=y; if(y!=0) tr[y].f=x; y=x;x=tr[x].f; } } void makeroot(int x) { access(x);splay(x,0); tr[x].fz=1-tr[x].fz; } void link(int x,int y) { makeroot(x); tr[x].f=y; access(x); } void cut(int x,int y) { makeroot(x); access(y); splay(y,0); tr[tr[y].son[0]].f=0;tr[y].son[0]=0; update(y); } int findroot(int x) { access(x);splay(x,0); while(tr[x].son[0]!=0) x=tr[x].son[0]; return x; } int getsum(int x,int y) { makeroot(x); access(y); splay(y,0); return tr[tr[y].son[0]].sum+tr[y].c; } void change(int x,int c) { makeroot(x); tr[x].c=c; update(x); } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&tr[i].c); tr[i].sum=tr[i].c; } int m; scanf("%d",&m); for(int i=1;i<=m;i++) { char st[11];int x,y; scanf("%s%d%d",st+1,&x,&y); if(st[1]=='b') { if(findroot(x)==findroot(y)) printf("no "); else link(x,y),printf("yes "); } if(st[1]=='e') { if(findroot(x)!=findroot(y)) printf("impossible "); else printf("%d ",getsum(x,y)); } if(st[1]=='p') change(x,y); } return 0; }