• bzoj1036: [ZJOI2008]树的统计Count(树链剖分+线段树维护)


    www.cnblogs.com/shaokele/


    bzoj1036: [ZJOI2008]树的统计Count##

      Time Limit: 10 Sec
      Memory Limit: 162 MB

    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”的操作,每行输出一个整数表示要求输出的结果。
     

    Sample Input###

      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
     

    Sample Output###

      4
      1
      2
      2
      10
      6
      5
      6
      5
      16
      

    题目地址:  bzoj1036: [ZJOI2008]树的统计Count

    题目大意:

      题目已经很清楚了
      

    题解:

      树链剖分裸题
      
      先把树轻重链剖分(两遍dfs)
      
      然后线段树维护区间最大值和区间和
      
      将剖出来的序列合并一下就好了
      


    AC代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define inf 0x7fffffff
    #define N 30005
    using namespace std;
    int n,Q,cnt,sz;
    int w[N],dep[N],size[N],head[N],fa[N];
    int pos[N],top[N];
    char ch[10];
    struct edge{
        int to,next;
    }e[N+N];
    struct seg{
        int l,r,mx,sum;
    }t[N<<2];
    void add_edge(int u,int v){
        e[++cnt]=(edge){v,head[u]};head[u]=cnt;
        e[++cnt]=(edge){u,head[v]};head[v]=cnt;
    }
    void dfs1(int u){
        size[u]=1;
        for(int i=head[u];i;i=e[i].next){
            if(e[i].to==fa[u])continue;
            dep[e[i].to]=dep[u]+1;
            fa[e[i].to]=u;
            dfs1(e[i].to);
            size[u]+=size[e[i].to];
        }
    }
    void dfs2(int u,int chain){
        int k=0;sz++;
        pos[u]=sz;
        top[u]=chain;
        for(int i=head[u];i;i=e[i].next)
            if(dep[e[i].to]>dep[u]&&size[e[i].to]>size[k])
                k=e[i].to;
        if(k==0)return;
        dfs2(k,chain);
        for(int i=head[u];i;i=e[i].next)
            if(dep[e[i].to]>dep[u]&&k!=e[i].to)
                dfs2(e[i].to,e[i].to);
    }
    void build(int l,int r,int id){
        t[id].l=l;t[id].r=r;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(l,mid,id<<1);
        build(mid+1,r,id<<1|1);
    }
    void change(int id,int k,int w){
        int l=t[id].l,r=t[id].r,mid=(l+r)>>1;
        if(l==r){
            t[id].sum=t[id].mx=w;
            return;
        }
        if(k<=mid)change(id<<1,k,w);
        else change(id<<1|1,k,w);
        t[id].sum=t[id<<1].sum+t[id<<1|1].sum;
        t[id].mx=max(t[id<<1].mx,t[id<<1|1].mx);
    }
    int querysum(int id,int L,int R){
        int l=t[id].l,r=t[id].r,mid=(l+r)>>1;
        if(l==L&&R==r)return t[id].sum;
        if(R<=mid)return querysum(id<<1,L,R);
        else if(L>mid)return querysum(id<<1|1,L,R);
        else return querysum(id<<1,L,mid)+querysum(id<<1|1,mid+1,R);
    }
    int querymx(int id,int L,int R){
        int l=t[id].l,r=t[id].r,mid=(l+r)>>1;
        if(l==L&&R==r)return t[id].mx;
        if(R<=mid)return querymx(id<<1,L,R);
        else if(L>mid)return querymx(id<<1|1,L,R);
        else return max(querymx(id<<1,L,mid),querymx(id<<1|1,mid+1,R));
    }
    int solvesum(int a,int b){
        int sum=0;
        while(top[a]!=top[b]){
            if(dep[top[a]]<dep[top[b]])swap(a,b);
            sum+=querysum(1,pos[top[a]],pos[a]);
            a=fa[top[a]];
        }
        if(pos[a]>pos[b])swap(a,b);
        sum+=querysum(1,pos[a],pos[b]);
        return sum;
    }
    int solvemx(int a,int b){
        int mx=-inf;
        while(top[a]!=top[b]){
            if(dep[top[a]]<dep[top[b]])swap(a,b);
            mx=max(mx,querymx(1,pos[top[a]],pos[a]));
            a=fa[top[a]];
        }
        if(pos[a]>pos[b])swap(a,b);
        mx=max(mx,querymx(1,pos[a],pos[b]));
        return mx;
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add_edge(u,v);
        }
        for(int i=1;i<=n;i++)scanf("%d",&w[i]);
        dfs1(1);
        dfs2(1,1);
         
        build(1,n,1);
        for(int i=1;i<=n;i++)
            change(1,pos[i],w[i]);
        scanf("%d",&Q);
        while(Q--){
            int x,y;scanf("%s%d%d",ch+1,&x,&y);
            if(ch[1]=='C'){
                w[x]=y;
                change(1,pos[x],y);
            }else
                if(ch[2]=='M')
                    printf("%d
    ",solvemx(x,y));
                else
                    printf("%d
    ",solvesum(x,y));
        }
        return 0;
    }
    
  • 相关阅读:
    JS立即执行函数: (function ( ){...})( ) 与 (function ( ){...}( )) 有区别?
    JS闭包和引用
    数据驱动测试二:使用TestNG和CSV文件进行数据驱动
    在SpringTest中将Mockito的mock对象通过spring注入使用
    Mockito各场景使用介绍
    mockito中两种部分mock的实现,spy、callRealMethod
    Docker学习笔记
    Docker实践(二):容器的管理(创建、查看、启动、终止、删除)
    mac 安装 RabbitMQ
    Mac 隐私与安全没有允许任何来源选项
  • 原文地址:https://www.cnblogs.com/shaokele/p/9085391.html
Copyright © 2020-2023  润新知