【例题】【动态树】NKOJ2250 树的统计

NKOJ2250 树的统计
时间限制 : 20000 MS 空间限制 : 265536 KB

问题描述
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
我们将以下面的形式来要求你对这棵树完成一些操作:
1.CHANGE u t : 把结点u的权值改为t
2.QMAX u v: 询问从点u到点v的路径上的节点的最大权值
3.QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身

输入格式
第一行为一个整数n,表示节点的个数。
接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。
接下来1行,为一个整数q,表示操作的总数。
接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。

输出格式
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

样例输入
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

样例输出
4
1
2
2
10
6
5
6
5
16

提示
对于100%的数据,保证1<=n<=30000,0<=q<=200000;
中途操作中保证每个节点的权值w在-30000到30000之间。

来源 【ZJOI2008】

思路:动态树…..
注意:
权值可能为负….
各点在link前视为森林,仍要保持各点存储信息的正确性

#include<cstdio>
#include<iostream>
using namespace std;
const int need=30004;

//..........................................
inline void inc(char &t)
{
    t=getchar();
    while(t==10||t==' '||t=='Q') t=getchar();
}
inline void in_(int &d)
{
    char t=getchar();bool mark=0;
    while(t<'0'||t>'9') {if(t=='-') mark=1;t=getchar();}
    for(d=0;!(t<'0'||t>'9');t=getchar()) d=(d<<1)+(d<<3)+t-'0';
    if(mark) d=-d;
}
inline void out_(int x)
{
    if(x<0) {x=-x;putchar('-');}
    if(x>=10) out_(x/10);
    putchar(x%10+'0');
}
//..........................................
int ls[need],rs[need],fa[need],val[need],sum[need],maxx[need];
bool lazy[need];

#define isroot(x) ((!(ls[fa[x]]==x||rs[fa[x]]==x))||fa[x]==0)
inline void NBHB(int x)
{
    sum[x]=maxx[x]=val[x];
    if(ls[x]) sum[x]+=sum[ls[x]],maxx[x]=max(maxx[ls[x]],maxx[x]);
    if(rs[x]) sum[x]+=sum[rs[x]],maxx[x]=max(maxx[rs[x]],maxx[x]);
}
inline void putdown(int x)
{
    lazy[x]=0;
    swap(ls[x],rs[x]);
    if(ls[x]) lazy[ls[x]]^=1;
    if(rs[x]) lazy[rs[x]]^=1;
}
int sss[need],tops;
void super_putdown(int x)
{
    sss[tops=1]=x;
    while(!isroot(x)) sss[++tops]=(x=fa[x]);
    for(;tops;tops--) if(lazy[sss[tops]]) putdown(sss[tops]);
}
inline void rotate(int x,int mm)
{
    int y=fa[x],z=fa[y];
    if(lazy[z]) putdown(z);
    if(lazy[y]) putdown(y);
    if(lazy[x]) putdown(x);
    if(!isroot(y)) ls[z]==y ? ls[z]=x :rs[z]=x;
    fa[x]=z;
    if(mm==1)
    {
        ls[y]=rs[x]; fa[rs[x]]=y;
        rs[x]=y; fa[y]=x;
    }
    else
    {
        rs[y]=ls[x]; fa[ls[x]]=y;
        ls[x]=y; fa[y]=x;
    }
    NBHB(y),NBHB(x);
}
void splay(int x)
{
    super_putdown(x);
    while(!isroot(x))
    {
        if(ls[fa[x]]==x) rotate(x,1);
        else rotate(x,2);
    }
}
void join(int x)
{
    for(int t=0;x;t=x,x=fa[x])
     splay(x),rs[x]=t,NBHB(x);
}
#define setroot(x) join(x),splay(x),lazy[x]^=1
#define link(x,y) setroot(x),fa[x]=y
//..........................................
int aa[need],bb[need];
//..........................................

int main()
{
    int n;in_(n);
    for(int a,b,i=1;i<n;i++) in_(aa[i]),in_(bb[i]);
    for(int i=1;i<=n;i++) in_(val[i]),sum[i]=maxx[i]=val[i];
    for(int i=1;i<n;i++) link(aa[i],bb[i]);//先更新各节点的值再link 
    int m;in_(m);
    char c;int a,b;
while(m--)
{
    inc(c),in_(a),in_(b);
    if(c=='C')
    {
        setroot(a);
        val[a]=b;
        NBHB(a);
    }
    else 
    {
        setroot(a);
        join(b);
        splay(b);
        if(c=='S') out_(sum[b]),putchar(10);
        else out_(maxx[b]),putchar(10);
    }
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值