[ZJOI2008]树的统计

[ZJOI2008]树的统计
=
    题目描述
    一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
    我们将以下面的形式来要求你对这棵树完成一些操作:
    I. CHANGE u t : 把结点u的权值改为t
    II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
    III. 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”的操作,每行输出一个整数表示要求输出的结果。
    说明
    对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节     点的权值w在-30000到30000之间。
解法
-
一到树剖裸题,套个线段树轻松AC(如果不会树剖[戳我](http://www.cnblogs.com/ljq-despair/p/8639462.html))
代码
-
```
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define rg register
#define mid ((l+r)>>1)
#define lc no<<1
#define rc no<<1|1
#define ls lc,l,mid
#define rs rc,mid+1,r
using namespace std;
il int gi(){
    rg char a=getchar();rg int b=0,f=1;
    while((a<'0'||a>'9')&&a!='-')a=getchar();
    if(a=='-')f=-1,a=getchar();
    while(a>='0'&&a<='9')b=b*10+a-'0',a=getchar();
    return b*f;
}
const int N=1e6;
int a[N],nex[N],to[N],w[N],dfn[N],fa[N],top[N],son[N],size[N],sum[N],ma[N],n,q,cnt;
void dfs1(int u){
    int s=0;
    size[u]=1;
    for(int i=a[u];i;i=nex[i]){
        int v=to[i];
        if(v==fa[u])continue;
        fa[v]=u;
        dfs1(v);
        size[u]+=size[v];
        if(size[v]>s)son[u]=v,s=size[v];
    }
}
void dfs2(int u,int TOP){
    top[u]=TOP;dfn[u]=++cnt;
    if(son[u])dfs2(son[u],TOP);
    for(int i=a[u];i;i=nex[i]){
        int v=to[i];
        if(v==fa[u]||v==son[u])continue;
        dfs2(v,v);
    }
}
void pushup(int no){sum[no]=sum[lc]+sum[rc];ma[no]=max(ma[lc],ma[rc]);}
void build(int no,int l,int r){
    if(l==r){
        sum[no]=ma[no]=w[l];
        return ;
    }
    build(ls);build(rs);
    pushup(no);
}
void update(int no,int l,int r,int u,int x){
    if(l==r){sum[no]=ma[no]=x;return ;}
    if(u<=mid)update(ls,u,x);
    else update(rs,u,x);
    pushup(no);
}
int query1(int no,int l,int r,int L,int R){
    if(l>=L&&r<=R)return sum[no];
    if(l>R||r<L)return 0;
    return query1(ls,L,R)+query1(rs,L,R);
}
int query2(int no,int l,int r,int L,int R){
    if(l>=L&&r<=R)return ma[no];
    if(r<L||l>R)return -1e9;
    return max(query2(ls,L,R),query2(rs,L,R));
}
int main(){
    n=gi();
    for(int i=1,t=0;i<n;++i){
        int u=gi(),v=gi();
        nex[++t]=a[u],to[t]=v,a[u]=t;
        nex[++t]=a[v],to[t]=u,a[v]=t;
    }
    dfs1(1);dfs2(1,1);
    for(int i=1;i<=n;++i)w[dfn[i]]=gi();
    q=gi();
    build(1,1,n);
    while(q--){
        char op=getchar();
        while(op!='C'&&op!='Q')op=getchar();
        if(op=='C'){int u=gi(),t=gi();update(1,1,n,dfn[u],t);}
        if(op=='Q'){
            op=getchar();int u=gi(),v=gi();
            if(op=='M'){
                int ans=-1e9;
                while(top[u]!=top[v]){
                    if(dfn[u]<dfn[v])swap(u,v);
                    ans=max(ans,query2(1,1,n,dfn[top[u]],dfn[u]));
                    u=fa[top[u]];
                }
                if(dfn[u]>dfn[v])swap(u,v);
                ans=max(ans,query2(1,1,n,dfn[u],dfn[v]));
                printf("%d\n",ans);
            }
            if(op=='S'){
                int ans=0;
                while(top[u]!=top[v]){
                    if(dfn[u]<dfn[v])swap(u,v);
                    ans+=query1(1,1,n,dfn[top[u]],dfn[u]);
                    u=fa[top[u]];
                }
                if(dfn[u]>dfn[v])swap(u,v);
                ans+=query1(1,1,n,dfn[u],dfn[v]);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

```

posted @ 2018-03-26 20:28  the_Despair  阅读(114)  评论(0编辑  收藏  举报