bzoj1036(树剖、LCT)

Description
  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成
一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 I
II. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身
Input
  输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有
一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作
的总数。接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
Output
  对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。


树剖模板题。
拿来练习LCT
附上代码:

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
#define ls ch[x][1]
#define rs ch[x][0]
int rd()
{
    int sum = 0;char c = getchar();bool flag = true;
    while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}
    while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();
    if(flag) return sum;
    else return -sum;
}
const int maxn = 4e5+6;
struct tree
{
    int ch[maxn][2],fa[maxn],v[maxn],mx[maxn],rev[maxn],sum[maxn];
    int q[maxn],top;
    void update(int x)
    {
        sum[x] = sum[ls] + sum[rs] + v[x];
        mx[x] = v[x];
        if(ls) mx[x] = max(mx[x],mx[ls]);
        if(rs) mx[x] = max(mx[x],mx[rs]);
    }
    bool isroot(int x){return ch[fa[x]][1] != x && ch[fa[x]][0] != x;}
    void pushdown(int x){if(rev[x])rev[x] ^= 1,swap(ls,rs),rev[ls] ^= 1,rev[rs] ^= 1;}
    void rorate(int x)
    {
        int y = fa[x],z = fa[y],k = ch[y][1] == x;
        if(!isroot(y)) ch[z][ch[z][1] == y] = x;
        ch[y][k] = ch[x][k^1]; fa[ch[x][k^1]] = y;
        ch[x][k^1] = y;        fa[x] = z;fa[y] = x;
        update(y);update(x);
    }
    void splay(int x)
    {
        int k = x;top = 0;
        while(1)
        {
            q[++top] = k;
            if(isroot(k)) break;
            k = fa[k];
        }
        while(top) pushdown(q[top--]);
        while(!isroot(x))
        {
            int y = fa[x],z = fa[y];
            if(!isroot(y)) rorate((ch[z][1]==y)^(ch[y][1] == x)?y:x);
            rorate(x);
        }
    }
    void access(int x){for(int t=0;x;x = fa[t=x]) splay(x),ch[x][1]=t,update(x);}
    void makeroot(int x){access(x);splay(x);rev[x] ^= 1;}
    void split(int x,int y){makeroot(x);access(y);splay(y);}
    void link(int x,int y){makeroot(x);fa[x] = y;}
    void cut(int x,int y)
    {
        makeroot(x);access(y);splay(y);
        fa[x] = ch[y][0] = 0;update(y);
    }
}T;
int n;
int a[30010],b[30010];
char s[20];
int main()
{
    n = rd();
    rep(i,1,n-1) a[i] = rd(),b[i] = rd();
    rep(i,1,n) T.v[i] = rd();
    rep(i,1,n-1) T.link(a[i],b[i]);
    int Q = rd();
    while(Q--)
    {
        scanf("%s",s+1);
        int a = rd(),b = rd();
        if(s[1] == 'C') {T.splay(a);T.v[a] = b;T.update(a);}
        else if(s[2] == 'M') {T.split(a,b);printf("%d\n",T.mx[b]);}
        else {T.split(a,b);printf("%d\n",T.sum[b]);}
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值