树链剖分/dfs序
树上单点修改+子树修改+链查询
其实用dfs序做也可以……
其实树链剖分就是一个特殊的dfs序嘛= =所以树链剖分也可以搞子树~(Orz ZYF)
至于为什么……你看在做剖分的时候不也是dfs下去的?然后只不过是先走重儿子,但本质上也是一个dfs序,所以dfs序能搞的子树操作,链剖也是兹瓷的~
然后随便水水就过了……
WA了一发:查询从x到1的权值和的时候,写成了while(top[x]),改成while(x)后就过了……
1 /************************************************************** 2 Problem: 4034 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:2192 ms 7 Memory:27956 kb 8 ****************************************************************/ 9 10 //BZOJ 4034 11 #include<vector> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 inline int getint(){ 23 int v=0,sign=1; char ch=getchar(); 24 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 25 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 26 return v*sign; 27 } 28 const int N=2e5+10,INF=~0u>>2; 29 typedef long long LL; 30 /******************tamplate*********************/ 31 32 33 int to[N<<1],nxt[N<<1],head[N],cnt; 34 void add(int x,int y){ 35 to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; 36 to[++cnt]=x; nxt[cnt]=head[y]; head[y]=cnt; 37 } 38 LL n,m,a[N]; 39 LL sm[N<<2],ad[N<<2]; 40 #define mid (l+r>>1) 41 #define L (o<<1) 42 #define R (o<<1|1) 43 inline void maintain(int o,int l,int r){ 44 sm[o]=sm[L]+sm[R]; 45 } 46 inline void Push_down(int o,int l,int r){ 47 if (ad[o]) { 48 ad[L]+=ad[o]; sm[L]+=ad[o]*(mid-l+1); 49 ad[R]+=ad[o]; sm[R]+=ad[o]*(r-mid); 50 ad[o]=0; 51 } 52 } 53 void update(int o,int l,int r,int ql,int qr,LL v){ 54 if (ql<=l && qr>=r) sm[o]+=v*(LL)(r-l+1),ad[o]+=v; 55 else{ 56 Push_down(o,l,r); 57 if (ql<=mid) update(L,l,mid,ql,qr,v); 58 if (qr>mid) update(R,mid+1,r,ql,qr,v); 59 maintain(o,l,r); 60 } 61 } 62 LL query_it(int o,int l,int r,int ql,int qr){ 63 if (ql<=l && qr>=r) return sm[o]; 64 else{ 65 LL ans=0; Push_down(o,l,r); 66 if (ql<=mid) ans+=query_it(L,l,mid,ql,qr); 67 if (qr>mid) ans+=query_it(R,mid+1,r,ql,qr); 68 return ans; 69 } 70 } 71 72 int top[N],fa[N],dep[N],tid[N],st[N],ed[N],son[N],size[N]; 73 void dfs(int x){ 74 size[x]=1; son[x]=0; 75 int mx=0; 76 for(int i=head[x];i;i=nxt[i]) 77 if (to[i]!=fa[x]){ 78 fa[to[i]]=x; 79 dep[to[i]]=dep[x]+1; 80 dfs(to[i]); 81 size[x]+=size[to[i]]; 82 if (size[to[i]]>mx) mx=size[to[i]],son[x]=to[i]; 83 } 84 } 85 int tot; 86 bool vis[N]; 87 void connect(int x,int f){ 88 vis[x]=1; 89 top[x]=f; 90 st[x]=tid[x]=++tot; 91 if (son[x]) connect(son[x],f); 92 for(int i=head[x];i;i=nxt[i]) 93 if (!vis[to[i]]) 94 connect(to[i],to[i]); 95 ed[x]=tot; 96 } 97 LL query(int x){ 98 LL ans=0; 99 while(x){ 100 ans+=query_it(1,1,n,tid[top[x]],tid[x]); 101 x=fa[top[x]]; 102 } 103 return ans; 104 } 105 int main(){ 106 #ifndef ONLINE_JUDGE 107 freopen("4034.in","r",stdin); 108 freopen("4034.out","w",stdout); 109 #endif 110 n=getint(); m=getint(); 111 F(i,1,n) a[i]=getint(); 112 F(i,2,n){ 113 int x=getint(),y=getint(); 114 add(x,y); 115 } 116 dfs(1); 117 connect(1,1); 118 F(i,1,n) update(1,1,n,tid[i],tid[i],a[i]); 119 int cmd,x,y; 120 F(i,1,m){ 121 cmd=getint(); x=getint(); 122 if (cmd==1){ 123 y=getint(); 124 update(1,1,n,tid[x],tid[x],y); 125 }else if (cmd==2){ 126 y=getint(); 127 update(1,1,n,st[x],ed[x],y); 128 }else{ 129 printf("%lld ",query(x)); 130 } 131 } 132 return 0; 133 }
4034: [HAOI2015]T2
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 265 Solved: 113
[Submit][Status][Discuss]
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
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
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
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
9
13
HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不
会超过 10^6 。