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提供
太久不写链剖线段树手已经生了..WA了好多次
跑的不算快(还是常数大吖..)
跟NOI2015 D1T2一个姿势
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 100100
#define lchild rt<<1,l,mid
#define rchild rt<<1|1,mid+1,r
#define ln rt<<1
#define rn rt<<1|1
#define GET (ch>='0'&&ch<='9')
#define LL long long
using namespace std;
int n,m,top,Top;
bool vis[MAXN];
int val[MAXN],chain[MAXN],bot[MAXN],num[MAXN],size[MAXN],fa[MAXN][18],deep[MAXN];
struct edge
{
int to;
edge *next;
}e[MAXN<<1],*prev[MAXN];
struct seg
{
int l,r;
LL sum,add;
}tree[MAXN<<2];
void push_up(int rt)
{
tree[rt].sum=tree[ln].sum+tree[rn].sum;
}
void build(int rt=1,int l=1,int r=n)
{
tree[rt].l=l;tree[rt].r=r;int mid=(l+r)>>1;
if (l==r) return;
build(lchild);build(rchild);
}
void push_down(int rt)
{
if (tree[rt].l==tree[rt].r) return;
if (tree[rt].add!=0)
{
tree[ln].add+=tree[rt].add;tree[rn].add+=tree[rt].add;
tree[ln].sum+=(LL)(tree[ln].r-tree[ln].l+1)*tree[rt].add;tree[rn].sum+=(LL)(tree[rn].r-tree[rn].l+1)*tree[rt].add;
tree[rt].add=0;
}
}
void modify(int rt,int l,int r,int delta)
{
push_down(rt);
int L=tree[rt].l,R=tree[rt].r,mid=(L+R)>>1;
if (l<=L&&R<=r)
{
tree[rt].sum+=(LL)(R-L+1)*delta;tree[rt].add+=delta;
return;
}
if (r<=mid) modify(ln,l,r,delta);
else
if (l>mid) modify(rn,l,r,delta);
else modify(ln,l,mid,delta),modify(rn,mid+1,r,delta);
push_up(rt);
}
LL query(int rt,int l,int r)
{
push_down(rt);
int L=tree[rt].l,R=tree[rt].r,mid=(L+R)>>1;
if (l<=L&&R<=r) return tree[rt].sum;
if (r<=mid) return query(ln,l,r);
if (l>mid) return query(rn,l,r);
return query(ln,l,mid)+query(rn,mid+1,r);
}
LL Query(int a,int b)
{
LL ret=0;
while (chain[a]!=chain[b])
{
ret+=query(1,num[chain[a]],num[a]);
a=fa[chain[a]][0];
}
ret+=query(1,num[b],num[a]);
return ret;
}
void insert(int u,int v)
{
e[++top].to=v;e[top].next=prev[u];prev[u]=&e[top];
}
void in(int &x)
{
int flag=1;char ch=getchar();x=0;
while (!GET) flag=ch=='-'?-1:flag,ch=getchar();
while (GET) x=x*10+ch-'0',ch=getchar();x*=flag;
}
void dfs1(int x)
{
size[x]=1;vis[x]=1;
for (int i=1;i<=17;i++)
if ((1<<i)<=deep[x]) fa[x][i]=fa[fa[x][i-1]][i-1];
else break;
for (edge *i=prev[x];i;i=i->next)
if (!vis[i->to]) deep[i->to]=deep[x]+1,fa[i->to][0]=x,dfs1(i->to),size[x]+=size[i->to];
}
void dfs2(int x,int last)
{
int t=0;
chain[x]=last;num[x]=++Top;bot[x]=Top;
for (edge *i=prev[x];i;i=i->next)
if (deep[i->to]>deep[x]&&size[i->to]>size[t]) t=i->to;
if (!t) return;dfs2(t,last);
for (edge *i=prev[x];i;i=i->next)
if (deep[i->to]>deep[x]&&i->to!=t) dfs2(i->to,i->to);
bot[x]=Top;
}
int main()
{
in(n);in(m);int opt,u,v;build();
for (int i=1;i<=n;i++) in(val[i]),bot[i]=i;
for (int i=1;i<n;i++) in(u),in(v),insert(u,v),insert(v,u);
dfs1(1);dfs2(1,1);
for (int i=1;i<=n;i++) modify(1,num[i],num[i],val[i]);
while (m--)
{
in(opt);
if (opt==1) in(u),in(v),modify(1,num[u],num[u],v);
if (opt==2) in(u),in(v),modify(1,num[u],bot[u],v);
if (opt==3) in(u),printf("%lld\n",Query(u,1));
}
}