BZOJ2843 - 极地旅行社
Description
给出\(n(n\leq3\times10^4)\)个独立的带权顶点,对其进行\(m(m\leq10^5)\)次操作:
- 连接两个不连通的节点。如果它们已经联通,输出
no
。 - 更改单点的权值。
- 求路径\((u,v)\)上的点权和。如果它们不连通,输出
impossible
。
Solution
一道link/cut tree裸题啦。
Code
//极地旅行社
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int const N=3e4+10;
int n,m;
int pre[N];
int find(int x) {return pre[x]==x?x:pre[x]=find(pre[x]);}
int fa[N],ch[N][2],val[N],sum[N]; bool rev[N];
int wh(int p) {return ch[fa[p]][1]==p;}
bool notRt(int p) {return p!=0&&ch[fa[p]][wh(p)]==p;}
void rever(int p) {rev[p]^=1; swap(ch[p][0],ch[p][1]);}
void update(int p) {sum[p]=val[p]+sum[ch[p][0]]+sum[ch[p][1]];}
void pushdw(int p) {if(rev[p]) rever(ch[p][0]),rever(ch[p][1]),rev[p]=0;}
void rotate(int p)
{
int q=fa[p],r=fa[q],w=wh(p);
fa[p]=r; if(notRt(q)) ch[r][wh(q)]=p;
fa[ch[q][w]=ch[p][w^1]]=q;
fa[ch[p][w^1]=q]=p;
update(q); update(p);
}
void pushdwRt(int p) {if(notRt(p)) pushdwRt(fa[p]); pushdw(p);}
void splay(int p)
{
pushdwRt(p);
for(int q=fa[p];notRt(p);rotate(p),q=fa[p]) if(notRt(q)) rotate(wh(p)==wh(q)?q:p);
update(p);
}
void access(int p) {for(int q=0;p;q=p,p=fa[p]) splay(p),ch[p][1]=q,update(p);}
void makeRt(int p) {access(p); splay(p),rever(p);}
void link(int p,int q) {makeRt(p); fa[p]=q; pre[find(p)]=find(q);}
int query(int p,int q) {makeRt(p),access(q); splay(q); return sum[q];}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&val[i]),sum[i]=val[i];
scanf("%d",&m);
for(int i=1;i<=n;i++) pre[i]=i;
for(int i=1;i<=m;i++)
{
char opt[15]; int x,y;
scanf("%s",opt); scanf("%d%d",&x,&y);
if(opt[0]=='b')
if(find(x)==find(y)) puts("no");
else link(x,y),puts("yes");
else if(opt[0]=='p') val[x]=y,splay(x);
else if(opt[0]=='e')
{
if(find(x)==find(y)) printf("%d\n",query(x,y));
else printf("impossible\n");
}
}
return 0;
}