BZOJ2843: 极地旅行社

【传送门: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\n");
            else link(x,y),printf("yes\n");
        }
        if(st[1]=='e')
        {
            if(findroot(x)!=findroot(y)) printf("impossible\n");
            else printf("%d\n",getsum(x,y));
        }
        if(st[1]=='p') change(x,y);
    }
    return 0;
}

 

posted @ 2018-03-28 11:49  Star_Feel  阅读(135)  评论(0编辑  收藏  举报