4034: [HAOI2015]T2
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 1897 Solved: 615
[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提供
题解:
树链剖分裸题,记录下每条链的长度即可,好久没打了,这个写的比较鬼畜….
开始出现了莫名的RE,真的是毫无道理的RE
code:
#include
#include
#include
#include
#include
using namespace std;
long long read()
{
long long x=0,f=1; char ch=getchar();
while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
#define maxn 200010
int n,m;
struct data{int next,to;}edge[maxn*2];
int head[maxn],cnt;long long va[maxn];
long long belong[maxn],size[maxn],deep[maxn],pl[maxn],sz,fa[maxn];
long long tree[maxn*4],del[maxn*4];
//---------------------------------------------------------------------
void add(int u,int v){cnt++;edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;}
void insert(int u,int v){add(u,v); add(v,u);}
//---------------------------------------------------------------------
void dfs_1(int now)
{
size[now]=1;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=fa[now])
{
fa[edge[i].to]=now; dfs_1(edge[i].to);
size[now]+=size[edge[i].to];
deep[now]=max(deep[now],deep[edge[i].to]);
}
}
void dfs_2(int now,int chain)
{
//printf("%d %d\n",now,chain);
deep[now]=pl[now]=++sz; belong[now]=chain; int k=0;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=fa[now] && size[k]if (!k) return; dfs_2(k,chain);deep[now]=max(deep[now],deep[k]);
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to==fa[now] || edge[i].to==k) continue;
else dfs_2(edge[i].to,edge[i].to),deep[now]=max(deep[now],deep[edge[i].to]);
}
//------------------------------------------------------------------------
inline void update(int now) {tree[now]=tree[now<<1]+tree[now<<1|1];}
inline void pushdown(int now,int l,int r)
{
if (!del[now]) return;
int mid=(l+r)>>1; int ln=mid-l+1,rn=r-mid;long long ad=0;
ad=del[now],del[now]=0,del[now<<1]+=ad,del[now<<1|1]+=ad,
tree[now<<1]+=ln*ad,tree[now<<1|1]+=rn*ad;
}
void segment_add(int now,int l,int r,int L,int R,long long val)
{
pushdown(now,l,r);
if (L<=l && R>=r) {del[now]+=val,tree[now]+=(r-l+1)*val;return;}
int mid=(l+r)>>1;
if (L<=mid) segment_add(now<<1,l,mid,L,R,val);
if (R>mid) segment_add(now<<1|1,mid+1,r,L,R,val);
update(now);
}
long long query(int now,int l,int r,int L,int R)
{
pushdown(now,l,r);
if (L<=l && R>=r) return tree[now];
int mid=(l+r)>>1;long long ans=0;
if (L<=mid) ans+=query(now<<1,l,mid,L,R);
if (R>mid) ans+=query(now<<1|1,mid+1,r,L,R);
return ans;
}
//-----------------------------------------------------------------------
void solvequery(int loc)
{
long long ans=0;
while (belong[loc]!=1)
ans+=query(1,1,n,pl[belong[loc]],pl[loc]),loc=fa[belong[loc]];
ans+=query(1,1,n,1,pl[loc]);
printf("%lld\n",ans);
}
//------------------------------------------------------------------------
int main()
{
n=read(),m=read();
for (int i=1; i<=n; i++) va[i]=read();
for (int u,v,i=1; i<=n-1; i++)
u=read(),v=read(),insert(u,v);
dfs_1(1); dfs_2(1,1);
// for (int i=1; i<=n; i++) printf("%d ",pl[i]);puts("");
// for (int i=1; i<=n; i++) printf("%d ",deep[i]);puts("");
// for (int i=1; i<=n; i++) printf("%d ",belong[i]);puts("");
for (int i=1; i<=n; i++)
segment_add(1,1,n,pl[i],pl[i],va[i]);
for (int i=1; i<=m; i++)
{
int opt=read(),x=read();long long a=0;
if (opt==1) a=read(),segment_add(1,1,n,pl[x],pl[x],a);
if (opt==2) a=read(),segment_add(1,1,n,pl[x],deep[x],a);
if (opt==3) solvequery(x);
}
return 0;
}