• BZOJ 4034 【HAOI2015】 T2


    Description

    有一棵点数为 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 ) 

    Output

     对于每个询问操作,输出该询问的答案。答案之间用换行隔开

    HINT

     对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。

      很久没有写过树剖了……找个板子题出来熟悉一下。

      树链剖分可以把树上的问题转化为序列上的问题,然后就可以用线段树等数据结构维护了。像这种不需要标记的区间修改、求值直接用树状数组就可以了。

      贴一个板子:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    #define maxn 100010
    
    using namespace std;
    typedef long long llg;
    
    int n,m,a[maxn],le[maxn],ri[maxn];
    int head[maxn],to[maxn<<1],next[maxn<<1],tt;
    int fa[maxn],top[maxn],siz[maxn],son[maxn],fc[maxn];
    llg c1[maxn],c2[maxn];
    
    int getint(){
    	int w=0;bool q=0;
    	char c=getchar();
    	while((c>'9'||c<'0')&&c!='-') c=getchar();
    	if(c=='-') c=getchar(),q=1;
    	while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
    	return q?-w:w;
    }
    
    void link(int x,int y){
    	to[++tt]=y;next[tt]=head[x];head[x]=tt;
    	to[++tt]=x;next[tt]=head[y];head[y]=tt;
    }
    
    inline void add(int x,int y){for(int i=x;i<=n;i+=i&(-i)) c1[i]+=y,c2[i]+=(llg)x*y;}
    inline llg sum(int x){
        llg ans(0);
        for(int i=x;i;i-=i&(-i)) ans+=(llg)(x+1)*c1[i]-c2[i];
        return ans;
    }
    
    void dfs(int u){
    	siz[u]=1;
    	for(int i=head[u],v;v=to[i],i;i=next[i])
    		if(v!=fa[u]){
    			fa[v]=u; dfs(v); siz[u]+=siz[v];
    			if(siz[v]>siz[son[u]]) son[u]=v;
    		}
    }
    
    void dfs(int u,int dd){
    	top[u]=dd; le[u]=fc[u]=++tt;
    	add(tt,a[u]),add(tt+1,-a[u]);
    	if(son[u]) dfs(son[u],dd);
    	for(int i=head[u],v;v=to[i],i;i=next[i])
    		if(!top[v]) dfs(v,v);
    	ri[u]=tt;
    }
    
    llg work(int u){
    	llg ans=0;
    	while(u){
    		int L=fc[top[u]],R=fc[u];
    		ans+=sum(R)-sum(L-1);
    		u=fa[top[u]];
    	}
    	return ans;
    }
    
    int main(){
    	File("a");
    	n=getint(); m=getint();
    	for(int i=1;i<=n;i++) a[i]=getint();
    	for(int i=1;i<n;i++) link(getint(),getint());
    	tt=0; dfs(1); dfs(1,1);
    	while(m--){
    		int ty=getint(),u=getint(),x;
    		if(ty==3) printf("%lld
    ",work(u));
    		else{
    			x=getint(); add(le[u],x);
    			if(ty==1) add(le[u]+1,-x);
    			else add(ri[u]+1,-x);
    		}
    	}
    	return 0;
    }
  • 相关阅读:
    结对第二次作业
    软件工程第四次作业
    软件工程第三次作业
    软件工程第二次作业
    软件工程第一次作业
    我的大学生活
    python实现栈和队列
    《数据结构与STL-第二章 线性表》读书笔记
    .net/c#常用框架/中间件简介(不定时更新)
    逆变与协变
  • 原文地址:https://www.cnblogs.com/lcf-2000/p/6057439.html
Copyright © 2020-2023  润新知