您的位置:首页 > 其它

bzoj 4034 [HAOI2015] T2(树链剖分,线段树)

2016-02-11 16:55 417 查看

4034: [HAOI2015]T2

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 1536 Solved: 508
[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

Sample Output

6

9

13

HINT

对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不

会超过 10^6 。

Source

鸣谢bhiaibogf提供

【思路】

  树链剖分,线段树

  线段树:区间和,区间修改add

【代码】

#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
#include<algorithm>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;

typedef long long LL;
const int N = 400000+10;

struct Node { LL sum,addv;
}T[N<<1];

int n,q,z,c
;
vector<int> g
;
//INIT
int top
,son
,dep
,fa
,siz
,w
,mxw
;
void dfs1(int u) {
son[u]=0; siz[u]=1;
for(int i=0;i<g[u].size();i++) {
int v=g[u][i];
if(v!=fa[u]) {
fa[v]=u , dep[v]=dep[u]+1;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int tp) {
top[u]=tp; w[u]=mxw[u]=++z;
if(son[u])
dfs2(son[u],tp),mxw[u]=max(mxw[u],mxw[son[u]]);
for(int i=0;i<g[u].size();i++) {
int v=g[u][i];
if(v!=fa[u] && v!=son[u])
dfs2(v,v),mxw[u]=max(mxw[u],mxw[v]);
}
}
//SEGMENT TREE
void pushdown(int u,int l,int r) {
if(T[u].addv && l<r) {
int lc=u<<1,rc=lc|1,M=(l+r)>>1;
T[lc].sum+=T[u].addv*(M-l+1);
T[rc].sum+=T[u].addv*(r-M);
T[lc].addv+=T[u].addv,T[rc].addv+=T[u].addv;
T[u].addv=0;
}
}
void update(int u,int L,int R,int l,int r,int x) {
pushdown(u,L,R);
if(l<=L && R<=r)
T[u].addv+=x , T[u].sum+=x*(R-L+1);
else {
int M=(L+R)>>1,lc=u<<1,rc=lc|1;
if(l<=M) update(lc,L,M,l,r,x);
if(M<r) update(rc,M+1,R,l,r,x);
T[u].sum=T[lc].sum+T[rc].sum;
}
}
LL query(int u,int L,int R,int l,int r) {
pushdown(u,L,R);
if(l<=L && R<=r) return T[u].sum;
else {
int M=(L+R)>>1; LL ans=0;
if(l<=M) ans+=query(u<<1,L,M,l,r);
if(M<r) ans+=query(u<<1|1,M+1,R,l,r);
return ans;
}
}
//Ê÷Á´ÆÊ·Ö
LL query(int u) {
LL sum=0;
while(top[u]!=1) {
sum+=query(1,1,z,w[top[u]],w[u]);
u=fa[top[u]];
}
sum+=query(1,1,z,1,w[u]);
return sum;
}

void read(int& x) {
char c=getchar(); int f=1; x=0;
while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
x*=f;
}
int main() {
//freopen("in.in","r",stdin);
//freopen("out.in","w",stdout);
read(n),read(q);
FOR(i,1,n) read(c[i]);
int u,v,x,op,y;
FOR(i,1,n-1) {
read(u),read(v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs1(1),dfs2(1,1);
FOR(i,1,n) update(1,1,z,w[i],w[i],c[i]);
while(q--) {
read(op),read(x);
if(op==1)
read(y),update(1,1,z,w[x],w[x],y);
else if(op==2)
read(y),update(1,1,z,w[x],mxw[x],y);
else
printf("%lld\n",query(x));
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: