zoukankan      html  css  js  c++  java
  • luogu P2590 [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”的操作,每行输出一个整数表示要求输出的结果。

    输入输出样例

    输入样例#1:
    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
    
    输出样例#1:
    4
    1
    2
    2
    10
    6
    5
    6
    5
    16
    

    说明

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

     树链剖分+线段树维护

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define maxn 100010
    #define inf 0x7fffffff
    struct Edge {
        int u,v,next;
        Edge(int u=0,int v=0,int next=0):
            u(u),v(v),next(next) {}
    }edge[maxn];
    struct Segment_Tree {
        int l,r,sum,Max;
    }t[maxn<<2];
    int head[maxn],cnt;
    int size[maxn],wson[maxn],dad[maxn];
    int depth[maxn],top[maxn],w[maxn];
    int tpos[maxn],pre[maxn],tot;
    inline int input() {
        char c=getchar();
        int x=0,flag=1;
        for(;c<'0'||c>'9';c=getchar())
            if(c=='-') flag=-1;
        for(;c>='0'&&c<='9';c=getchar())
            x=(x<<1)+(x<<3)+c-'0';
        return x*flag;
    }
    inline void Add_edge(int u,int v) {
        edge[++cnt]=Edge(u,v,head[u]);
        head[u]=cnt;
        edge[++cnt]=Edge(v,u,head[v]);
        head[v]=cnt;
        return;
    }
    void dfs1(int u,int f) {
        size[u]=1;
        for(int i=head[u];i;i=edge[i].next) {
            int v=edge[i].v;
            if(v==f) continue;
            depth[v]=depth[u]+1;
            dad[v]=u;
            dfs1(v,u);
            size[u]+=size[v];
            if(size[v]>size[wson[u]])
                wson[u]=v;
        }
        return;
    }
    void dfs2(int u,int chain) {
        tpos[u]=++tot;
        pre[tot]=u;
        top[u]=chain;
        if(wson[u]) dfs2(wson[u],chain);
        for(int i=head[u];i;i=edge[i].next) {
            int v=edge[i].v;
            if(v==dad[u]||v==wson[u]) continue;
            dfs2(v,v);
        }
        return;
    }
    void UpData(int now) {
        int lc=now<<1,rc=now<<1|1;
        t[now].Max=max(t[lc].Max,t[rc].Max);
        t[now].sum=t[lc].sum+t[rc].sum;
        return;
    }
    void Build(int now,int L,int R) {
        t[now].l=L,t[now].r=R;
        if(L==R) {
            t[now].sum=w[pre[L]];
            t[now].Max=w[pre[L]];
            return;
        }
        int mid=L+R>>1,lc=now<<1,rc=now<<1|1;
        Build(lc,L,mid);
        Build(rc,mid+1,R);
        UpData(now);
        return;
    }
    void Modify(int now,int pos,int x) {
        int l=t[now].l,r=t[now].r;
        if(l==r) {
            t[now].Max=x;
            t[now].sum=x;
            return;
        }
        int mid=l+r>>1,lc=now<<1,rc=now<<1|1;
        if(pos<=mid) Modify(lc,pos,x);
        else Modify(rc,pos,x);
        UpData(now);
        return;
    }
    int Query(int now,int L,int R,bool flag) {
        int l=t[now].l,r=t[now].r;
        int mid=l+r>>1,lc=now<<1,rc=now<<1|1;
        if(flag==1) {
            if(l==L&&R==r) return t[now].sum;
            if(R<=mid) return Query(lc,L,R,1);
            else if(L>mid) return Query(rc,L,R,1);
            else {
                int x=Query(lc,L,mid,1);
                int y=Query(rc,mid+1,R,1);
                return x+y;
            }
        } else {
            if(l==L&&R==r) return t[now].Max;
            if(R<=mid) return Query(lc,L,R,0);
            else if(L>mid) return Query(rc,L,R,0);
            else {
                int x=Query(lc,L,mid,0);
                int y=Query(rc,mid+1,R,0);
                return max(x,y);
            }
        }
        UpData(now);
    }
    int QSUM(int u,int v) {
        int sum=0;
        while(top[u]!=top[v]) {
            if(depth[top[u]]<depth[top[v]])
                swap(u,v);
            sum+=Query(1,tpos[top[u]],tpos[u],1);
            u=dad[top[u]];
        }
        if(depth[u]<depth[v]) swap(u,v);
        sum+=Query(1,tpos[v],tpos[u],1);
        return sum;
    }
    int QMAX(int u,int v) {
        int Max=-inf;
        while(top[u]!=top[v]) {
            if(depth[top[u]]<depth[top[v]])
                swap(u,v);
            int t=Query(1,tpos[top[u]],tpos[u],0);
            Max=max(Max,t);
            u=dad[top[u]];
        }
        if(depth[u]<depth[v]) swap(u,v);
        int t=Query(1,tpos[v],tpos[u],0);
        return max(Max,t);
    }
    int main() {
        int n=input();
        for(int i=1;i<n;i++) {
            int u=input(),v=input();
            Add_edge(u,v);
        }
        for(int i=1;i<=n;i++)
            w[i]=input();
        depth[1]=1;
        dad[1]=1;
        dfs1(1,-1);
        dfs2(1,1);
        Build(1,1,n);
        for(int i=input();i>=1;i--) {
            char op[10];
            int x,y;
            scanf("%s%d%d",op,&x,&y);
            if(op[1]=='H') Modify(1,tpos[x],y);
            if(op[1]=='S') printf("%d
    ",QSUM(x,y));
            if(op[1]=='M') printf("%d
    ",QMAX(x,y));
        }
        return 0;
    }
  • 相关阅读:
    [LeetCode]题解(python):053-Maximum Subarray
    [LeetCode]题解(python):052-N-Queens II
    [LeetCode]题解(python):051-N-Queens
    [LeetCode]题解(python):050-Pow(x, n)
    [LeetCode]题解(python):049-Group Anagrams
    [LeetCode]题解(python):048-Rotate Image
    构建之法阅读笔记01
    软件工程第一周开课博客
    第二周作业:返回一个整数数组中最大子数组的和
    第二周javaweb学习进度表
  • 原文地址:https://www.cnblogs.com/sssy/p/7159248.html
Copyright © 2011-2022 走看看