• 数的统计count(bzoj1036)


    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
    /*
      第一次写树链剖分,大概就是把一棵树分成很多链,然后把这些链首尾相接,形成一个序列,然后再用其他数据结构维护这个序列。
      具体操作是把边分为轻边和重边,重边是某个节点与他的最大字数的根节点的连边,由重边构成的链叫重链。
      先说一下几个数组的意思:
      size[]数组,用来保存以x为根的子树节点个数
      top[]数组,用来保存当前节点的所在链的顶端节点
      son[]数组,用来保存重儿子
      dep[]数组,用来保存当前节点的深度
      fa[]数组,用来保存当前节点的父亲
      pos[]数组,用来保存树中每个节点剖分后的新编号
    第一遍dfs:求出树每个结点的深度dep[x],其为根的子树大小size[x]
    第二遍dfs:ž根节点为起点,向下拓展构建重链
    选择最大的一个子树的根继承当前重链
    其余节点,都以该节点为起点向下重新拉一条重链
    给每个结点分配一个位置编号,每条重链就相当于一段区间,用数据结构去维护。
    把所有的重链首尾相接,放到同一个数据结构上,然后维护这一个整体即可
    
    修改操作
    1、单独修改一个点的权值
    根据其编号直接在数据结构中修改就行了。
    2、修改点u和点v的路径上的权值
    (1)若u和v在同一条重链上
    直接用数据结构修改pos[u]至pos[v]间的值。
    (2)若u和v不在同一条重链上
    一边进行修改,一边将u和v往同一条重链上靠,然后就变成了情况(1)。
    
    查询操作
    查询操作的分析过程同修改操作
    */
    #include<cstdio>
    #include<iostream>
    #define N 300010
    #define inf 1000000000
    #define lson l,mid,now*2
    #define rson mid+1,r,now*2+1
    using namespace std;
    int pos[N],son[N],top[N],dep[N],size[N],fa[N];
    int head[N],v[N],n,m,sum[N*4],mx[N*4],sz;
    struct node{
        int to,pre;
    };node e[N*2];
    void add(int i,int x,int y){
        e[i].pre=head[x];
        e[i].to=y;
        head[x]=i;
    }
    void dfs1(int x){
        size[x]=1;
        for(int i=head[x];i;i=e[i].pre){
            if(e[i].to==fa[x])continue;
            dep[e[i].to]=dep[x]+1;
            fa[e[i].to]=x;
            dfs1(e[i].to);
            size[x]+=size[e[i].to];
        }
    }
    void dfs2(int x,int ding){
        int k=0;sz++;
        pos[x]=sz;top[x]=ding;
        for(int i=head[x];i;i=e[i].pre)
            if(dep[e[i].to]>dep[x]&&size[e[i].to]>size[k])
                 k=e[i].to;
        if(!k)return;
        dfs2(k,ding);
        for(int i=head[x];i;i=e[i].pre)
            if(dep[e[i].to]>dep[x]&&e[i].to!=k)
                dfs2(e[i].to,e[i].to);
    }
    void push_up(int now){
        sum[now]=sum[now*2]+sum[now*2+1];
        mx[now]=max(mx[now*2],mx[now*2+1]);
    }
    void change(int x,int y,int l,int r,int now){
        if(l==r){
            sum[now]=mx[now]=y;return;
        }
        int mid=(l+r)>>1;
        if(x<=mid)change(x,y,lson);
        else change(x,y,rson);
        push_up(now);
    }
    int quirysum(int x,int y,int l,int r,int now){
        if(l>=x&&r<=y)return sum[now];
        int mid=(l+r)>>1,tot=0;
        if(x<=mid)tot+=quirysum(x,y,lson);
        if(y>mid)tot+=quirysum(x,y,rson);
        return tot;
    }
    int quirymx(int x,int y,int l,int r,int now){
        if(l>=x&&r<=y)return mx[now];
        int mid=(l+r)>>1,tot=-inf;
        if(x<=mid)tot=max(tot,quirymx(x,y,lson));
        if(y>mid)tot=max(tot,quirymx(x,y,rson));
        return tot;
    }
    int solvesum(int x,int y){
        int tot=0;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            tot+=quirysum(pos[top[x]],pos[x],1,n,1);
            x=fa[top[x]];
        }
        if(pos[x]>pos[y])swap(x,y);
        tot+=quirysum(pos[x],pos[y],1,n,1);
        return tot;
    }
    int solvemx(int x,int y){
        int mx=-inf;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]])swap(x,y);
            mx=max(mx,quirymx(pos[top[x]],pos[x],1,n,1));
            x=fa[top[x]];
        }
        if(pos[x]>pos[y])swap(x,y);
        mx=max(mx,quirymx(pos[x],pos[y],1,n,1));
        return mx;
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int x,y;scanf("%d%d",&x,&y);
            add(i*2-1,x,y);add(i*2,y,x);
        }
        for(int i=1;i<=n;i++)scanf("%d",&v[i]);
        dfs1(1);dfs2(1,1);
        for(int i=1;i<=n;i++)change(pos[i],v[i],1,n,1);
        scanf("%d",&m);char ch[10];
        while(m--){
            int x,y;scanf("%s%d%d",ch,&x,&y);
            if(ch[0]=='C'){v[x]=y;change(pos[x],y,1,n,1);}
            else {
                if(ch[1]=='M')printf("%d
    ",solvemx(x,y));
                else printf("%d
    ",solvesum(x,y));
            }
        }
        return 0;
    }

    最后贴一个很好的ppt:http://wenku.baidu.com/link?url=SGLjpJtYbJ0HxDYlU_GMXE1qCFS0gbmpDGWPxI7mQuNAsJP0y872mNKwpZ8P054g5XMhFGZbMUjZvN5hcnxFFUEfGBj6-tnkpnJvnVSlqGS

    新学了LCT,也可以搞这个题目。

    #include<cstdio>
    #include<iostream>
    #define N 30010
    #define inf 1000000000
    using namespace std;
    int u[N],v[N],w[N],c[N][2],fa[N],mx[N],sum[N],rev[N],st[N],n,m;
    bool isroot(int x){
        return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
    }
    void update(int x){
        int l=c[x][0],r=c[x][1];
        sum[x]=w[x]+sum[l]+sum[r];
        mx[x]=max(w[x],max(mx[l],mx[r]));
    }
    void pushdown(int x){
        int l=c[x][0],r=c[x][1];
        if(rev[x]){
            rev[x]^=1;rev[l]^=1;rev[r]^=1;
            swap(c[x][0],c[x][1]);
        }
    }
    void rotate(int x){
        int y=fa[x],z=fa[y],l,r;
        if(c[y][0]==x) l=0;else l=1;r=l^1;
        if(!isroot(y)){
            if(c[z][0]==y) c[z][0]=x;else c[z][1]=x;
        }
        fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
        c[y][l]=c[x][r];c[x][r]=y;
        update(y);update(x);
    }
    void splay(int x){
        int top=0;st[++top]=x;
        for(int i=x;!isroot(i);i=fa[i])
            st[++top]=fa[i];
        for(int i=top;i;i--) pushdown(st[i]);
        while(!isroot(x)){
            int y=fa[x],z=fa[y];
            if(!isroot(y)){
                if(c[y][0]==x^c[z][0]==y) rotate(x);
                else rotate(y);
            }
            rotate(x);
        }
    }
    void access(int x){
        for(int t=0;x;t=x,x=fa[x])
            splay(x),c[x][1]=t,update(x);
    }
    void makeroot(int x){
        access(x);splay(x);rev[x]^=1;
    }
    void join(int x,int y){
        makeroot(x);fa[x]=y;splay(x);
    }
    void query(int x,int y){//在查询的时候,先将x转到根节点,再将y转到根节点,此时y的值就是所求值 
        makeroot(x);access(y);splay(y);
    }
    int main(){
        scanf("%d",&n);mx[0]=-inf;//mx忘记赋最小值了,1WA 
        for(int i=1;i<n;i++)
            scanf("%d%d",&u[i],&v[i]);
        for(int i=1;i<=n;i++){
            scanf("%d",&w[i]);
            sum[i]=mx[i]=w[i];
        }
        for(int i=1;i<n;i++)
            join(u[i],v[i]);
        scanf("%d",&m);
        char ch[10];int x,y;
        for(int i=1;i<=m;i++){
            scanf("%s%d%d",ch,&x,&y);
            if(ch[0]=='C'){
                splay(x);
                w[x]=y;
                update(x);
            }
            else if(ch[0]=='Q'&&ch[1]=='M'){
                query(x,y);
                printf("%d
    ",mx[y]);
            }
            else {
                query(x,y);
                printf("%d
    ",sum[y]);
            }
        }
        return 0;
    }
  • 相关阅读:
    java类的继承
    Java数组运算
    Eclipse问题提示
    oracle的insert的时候&符号如何插入(转义)
    修改数据库用户名--CMD环境执行有效
    java环境变量设置
    当前时间时间戳以及10分钟后的时间戳
    复选框事件
    分享到
    多物体运动
  • 原文地址:https://www.cnblogs.com/harden/p/6194032.html
Copyright © 2020-2023  润新知