BZOJ2843 - 极地旅行社

Portal

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;
}
posted @ 2018-03-07 08:04  VisJiao  阅读(150)  评论(0编辑  收藏  举报