• [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 ",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 ",ans);
                }
            }
        }
        return 0;
    }

    ```

  • 相关阅读:
    JAVA网络编程入门
    悲观锁和乐观锁
    原子性---Atomic
    volatile关键字
    leetcode_111. 二叉树的最小深度
    leetcode_110. 平衡二叉树
    leetcode_108. 将有序数组转换为二叉搜索树
    leetcode_107. 二叉树的层次遍历 II
    leetcode_104. 二叉树的最大深度
    leetcode_101. 对称二叉树
  • 原文地址:https://www.cnblogs.com/ljq-despair/p/8653511.html
Copyright © 2020-2023  润新知