1180: [CROATIAN2009]OTOCI/2843: 极地旅行社

题目链接

题目大意:一些点,每个点有一个权值。有三种操作:连边,单点修改权值,求两点之间路径上点的权值和

题解:套路LCT~~~

我的收获:……

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int M=30005;
const int INF=1e9;

int n,m,y;
int a[M],sum[M];
int c[M][2],fa[M],st[M];
bool rev[M];

struct Link_Cut_Tree{
    inline bool f(int x){return c[fa[x]][1]==x;}
    inline bool isr(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
    inline void pushup(int x){sum[x]=sum[c[x][0]]+sum[c[x][1]]+a[x];}
    inline void pushdown(int x)
    {
        if(!rev[x]) return ;
        int &l=c[x][0],&r=c[x][1];
        rev[l]^=1;rev[r]^=1;swap(l,r);
        rev[x]=0;
    }
    void rotate(int x)
    {
        int p=fa[x],g=fa[p],r;
        bool k=f(x),m=f(p);r=c[x][k^1];
        if(!isr(p)) c[g][m]=x;
        fa[x]=g,c[x][k^1]=p;
        fa[p]=x,c[p][k]=r;
        if(r) fa[r]=p;
        pushup(p),pushup(x);
    }
    void maintain(int x)
    {
        int top=0;st[++top]=x;
        for(int i=x;!isr(i);i=fa[i]) st[++top]=fa[i];
        for(int i=top;i>=1;i--) pushdown(st[i]);
    } 
    void splay(int x)
    {
        maintain(x);
        for(;!isr(x);rotate(x))
            if(!isr(fa[x])) rotate(f(x)==f(fa[x])?fa[x]:x);
    } 
    void access(int x){for(y=0;x;y=x,x=fa[x]) splay(x),c[x][1]=y,pushup(x);} 
    void rever(int x){access(x);splay(x);rev[x]^=1;}
    void link(int x,int y){rever(y);fa[y]=x;}
    void cut(int x,int y){rever(x);access(y);splay(y);fa[x]=c[y][0]=0;}
    int fdrt(int x){access(x);splay(x);for(y=x;c[y][0];y=c[y][0]);return y;}
}T;

void work()
{
    char opt[15];int u,v;
    while(m--)
    {
        scanf("%s%d%d",opt,&u,&v);
        if(opt[0]=='b'){
            if(T.fdrt(u)==T.fdrt(v)) puts("no");
            else T.link(u,v),puts("yes");
        }
        if(opt[0]=='p') a[u]=v,T.access(u),T.splay(u);
        if(opt[0]=='e'){
            if(T.fdrt(u)==T.fdrt(v)){
                T.rever(u);
                T.access(v),T.splay(v);
                printf("%d\n",sum[v]);
            }
            else puts("impossible");
        }
    }
} 
void init()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=a[i];
    scanf("%d",&m);
}

int main()
{
    init();
    work();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值