zoukankan      html  css  js  c++  java
  • [HAOI2015]树上操作

    有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
    操作,分为三种:
    操作 1 :把某个节点 x 的点权增加 a 。
    操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
    Input
    第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1
    行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
    第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
    N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6
    Output
    对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
    Sample Input
    5 5
    1 2 3 4 5
    1 2
    1 4
    2 3
    2 5
    3 3
    1 2 1
    3 5
    2 1 2
    3 3
    Sample Output
    6
    9
    13

    /*
    有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
    操作,分为三种:
    操作 1 :把某个节点 x 的点权增加 a 。
    操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
     
    int n,m,p,x,a,tot,head[100005],cnt,value[100005],u,v;
    int son[100005],fa[100005],id[100005],size[100005],top[100005],dep[100005],mx[100005];
    long long lazy[400005],sum[400005];
     
    struct edge
    {
        int v,next;
    } s[200005];
     
    void pushdown(int now,int l,int r)
    {
        if(l==r) return;
        int mid=(l+r)/2;
        lazy[now*2]+=lazy[now];
        lazy[now*2+1]+=lazy[now];
        sum[now*2]+=lazy[now]*(mid-l+1);
        sum[now*2+1]+=lazy[now]*(r-mid);
        lazy[now]=0;
    }
     
    void add(int now,int l,int r,int x,int y,long long k)
    {
        if(lazy[now]) 
    	    pushdown(now,l,r);
        if(l==x&&y==r)
        {
            lazy[now]+=k;
            sum[now]+=k*(r-l+1);
            return;
        }
        int mid=(l+r)/2;
        if(x<=mid) add(now*2,l,mid,x,min(mid,y),k);
        if(y>mid) add(now*2+1,mid+1,r,max(mid+1,x),y,k);
        sum[now]=sum[now*2]+sum[now*2+1];
    }
     
    long long query(int now,int l,int r,int x,int y)
    {
        if(lazy[now]) 
    	   pushdown(now,l,r);
        if(l==x&&y==r) 
    	   return sum[now];
        int mid=(l+r)/2;
        long long ans=0;
        if(x<=mid) 
    	   ans+=query(now*2,l,mid,x,min(mid,y));
        if(y>mid) 
    	   ans+=query(now*2+1,mid+1,r,max(x,mid+1),y);
        return ans;
    }
     
    void Query(int x) //查询从x点到根结点所有点权和 
    {
        long long ans=0;
        while(top[x]!=1)
        {
            ans+=query(1,1,n,id[top[x]],id[x]);
            x=fa[top[x]];
        }
        ans+=query(1,1,n,1,id[x]); 
        printf("%lld
    ",ans);
        return;
    }
     
    void dfs_1(int now,int father)
    {
        size[now]=1;
        fa[now]=father;
        for(int i=head[now];i!=0;i=s[i].next)
        {
            int to=s[i].v;
            if(to==father) continue;
            dfs_1(to,now);
            size[now]+=size[to];
            if(size[to]>size[son[now]]) 
    		   son[now]=to;
        }
    }
     
    void dfs_2(int now,int v)//树链剖分过程 
    {
        top[now]=v;
        id[now]=mx[now]=++tot;//记下在线段树的位置 
        if(son[now])
            dfs_2(son[now],v), mx[now]=max(mx[now],mx[son[now]]);
            //mx[now]记下最后在线段树中出现的位置 
        for(int i=head[now];i!=0;i=s[i].next)
        {
            int to=s[i].v;
            if(to==son[now]||to==fa[now]) continue;
            dfs_2(to,to);
            mx[now]=max(mx[now],mx[to]);
        }
    }
     
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&value[i]);
        for(int i=1;i<=n-1;i++)
        {
            scanf("%d%d",&u,&v);
            s[++cnt].v=v; s[cnt].next=head[u]; head[u]=cnt;
            s[++cnt].v=u; s[cnt].next=head[v]; head[v]=cnt;
        }
        dfs_1(1,0);
        dfs_2(1,1);
        for(int i=1;i<=n;i++)//建立线段树 
            add(1,1,n,id[i],id[i],value[i]);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&p,&x);
            if(p==1) //某个节点 x 的点权增加 a 。
            {
                scanf("%d",&a);
                add(1,1,n,id[x],id[x],a);
            }
            else if(p==2)
            {
                scanf("%d",&a); 
    			//把某个节点 x 为根的子树中所有点的点权都增加 a
                add(1,1,n,id[x],mx[x],a);
            }
            else
                Query(x);
        }
        return 0;
    }
    

      

  • 相关阅读:
    Discuz X 2.5 点点(伪静态)
    jq 、xml 省市级联动
    php memcache 初级使用(2)
    关于windows虚拟内存管理的页目录自映射
    SharePoint 2010 网络上的开发经验和资源
    SharePoint 2010 Reporting Services 报表服务器正在内置 NT AUTHORITY\SYSTEM 账户下运行 解决方法
    SharePoint 2010 Reporting Services 报表服务器无法解密用于访问报表服务器数据库中的敏感数据或加密数据的对称密钥 解决方法
    Active Directory Rights Management Services (AD RMS)无法检索证书层次结构。 解决方法
    SharePoint 2010 Reporting Services 报表服务器实例没有正确配置 解决方法
    SharePoint 2010 页面引用 Reporting Services 展现 List 报表
  • 原文地址:https://www.cnblogs.com/cutemush/p/11857723.html
Copyright © 2011-2022 走看看