BZOJ 1180 CROATIAN 2009 OTOCI/2843 极地旅行社 LCT

题目大意:给出一些初始相互分离的岛,有三个操作,1.分析两点是否联通,如果不连通,在之间连一条边。2.更改一个点的权值。3.询问两点之间路径上所有点的点权和。


思路:基本算是LCT的模板题了吧,好久没写了,基本都要忘了,这是照别人代码写的。。。


CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 30010
using namespace std;
 
struct SplayTree{
    SplayTree *son[2],*father;
    int val,sum;
    bool reverse;
     
    SplayTree(int _);
    bool Check() {
        return father->son[1] == this;
    }
    void Reverse() {
        reverse ^= 1;
        swap(son[0],son[1]);
    }
    void PushUp();
    void PushDown();
}none(0),*nil = &none,*tree[MAX];
SplayTree:: SplayTree(int _) {
    val = sum = _;
    reverse = false;
    son[0] = son[1] = father = nil;
}
void SplayTree:: PushDown() {
    if(father->son[0] == this || father->son[1] == this)
        father->PushDown();
    if(reverse) {
        son[0]->Reverse();
        son[1]->Reverse();
        reverse = false;
    }
}
void SplayTree:: PushUp() {
    sum = son[0]->sum + son[1]->sum + val;
}
 
int points,asks;
 
char s[20];
 
inline void Rotate(SplayTree *a,bool dir)
{
    SplayTree *f = a->father;
    f->son[!dir] = a->son[dir];
    f->son[!dir]->father = f;
    a->son[dir] = f;
    a->father = f->father;
    if(f->father->son[0] == f || f->father->son[1] == f)
        f->father->son[f->Check()] = a;
    f->father = a;
    f->PushUp();
}
 
inline void Splay(SplayTree *a)
{
    a->PushDown();
    while(a->father->son[0] == a || a->father->son[1] == a) {
        SplayTree *f = a->father;
        if(f->father->son[0] != f && f->father->son[1] != f)
            Rotate(a,!a->Check());
        else if(!f->Check()) {
            if(!a->Check())
                Rotate(f,true),Rotate(a,true);
            else    Rotate(a,false),Rotate(a,true);
        }
        else {
            if(a->Check())
                Rotate(f,false),Rotate(a,false);
            else    Rotate(a,true),Rotate(a,false);
        }
    }
    a->PushUp();
}
 
inline void Access(SplayTree *a)
{
    SplayTree *temp = nil;
    while(a != nil) {
        Splay(a);
        a->son[1] = temp;
        a->PushUp();
        temp = a;
        a = a->father;
    }
}
 
inline SplayTree *Find(SplayTree *a)
{
    while(a->father != nil)
        a = a->father;
    return a;
}
 
inline void ToRoot(SplayTree *a)
{
    Access(a);
    Splay(a);
    a->Reverse();
}
 
inline void Link(SplayTree *x,SplayTree *y)
{
    ToRoot(x);
    x->father = y;
}
 
int main()
{
    cin >> points;
    for(int x,i = 1; i <= points; ++i) {
        scanf("%d",&x);
        tree[i] = new SplayTree(x);
    }
    cin >> asks;
    for(int x,y,i = 1; i <= asks; ++i) {
        scanf("%s%d%d",s,&x,&y);
        if(s[0] == 'b') {
            SplayTree *fx = Find(tree[x]);
            SplayTree *fy = Find(tree[y]);
            if(fx == fy)
                puts("no");
            else {
                puts("yes");
                Link(tree[x],tree[y]);
            }
        }
        else if(s[0] == 'p') {
            Splay(tree[x]);
            tree[x]->val = y;
            tree[x]->PushUp();
        }
        else {
            SplayTree *fx = Find(tree[x]);
            SplayTree *fy = Find(tree[y]);
            if(fx != fy)
                puts("impossible");
            else {
                ToRoot(tree[x]);
                Access(tree[y]);
                Splay(tree[y]);
                printf("%d\n",tree[y]->sum);
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值