4034: [HAOI2015]T2
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 3431 Solved: 1069
[ 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 。
Source
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 1E5 + 10;
const int T = 4;
typedef long long LL;
int n,m,dfs_clock,fa[maxn][18],L[maxn],pos[maxn],siz[maxn]
,dfn[maxn],va[maxn],Nex[maxn],ot[maxn],Num[maxn],len[maxn];
bool Huge[maxn];
LL c[maxn*T],Add[maxn*T];
vector <int> v[maxn];
void Dfs1(int x,int from)
{
int ma = 0,po; siz[x] = 1;
for (int i = 0; i < v[x].size(); i++)
{
int to = v[x][i];
if (to == from) continue;
Dfs1(to,x); siz[x] += siz[to];
if (siz[to] > ma) ma = siz[to],po = to;
}
if (ma) Nex[x] = po,Huge[po] = 1;
}
void Dfs2(int x,int from)
{
for (int i = 1; i < 18; i++) fa[x][i] = fa[fa[x][i-1]][i-1];
dfn[x] = ++dfs_clock; Num[dfs_clock] = x;
if (Nex[x])
{
len[Nex[x]] = len[x] + 1;
L[Nex[x]] = L[x] + 1; fa[Nex[x]][0] = x; Dfs2(Nex[x],x);
if (Huge[x]) len[x] = len[Nex[x]],pos[x] = pos[Nex[x]] - 1;
}
else if (Huge[x]) pos[x] = len[x];
for (int i = 0; i < v[x].size(); i++)
{
int to = v[x][i];
if (to == from || to == Nex[x]) continue;
L[to] = L[x] + 1; fa[to][0] = x; Dfs2(to,x);
}
ot[x] = dfs_clock;
}
void pushdown(int o,int l,int r)
{
if (!Add[o]) return;
LL len = r - l + 1;
c[o] += Add[o]*len;
if (l == r) {Add[o] = 0; return;}
Add[o<<1] += Add[o];
Add[o<<1|1] += Add[o];
Add[o] = 0;
}
void Build(int o,int l,int r)
{
if (l == r) {c[o] = va[Num[l]]; return;}
int mid = (l + r) >> 1;
Build(o<<1,l,mid); Build(o<<1|1,mid+1,r);
c[o] = c[o<<1] + c[o<<1|1];
}
void Modify(int o,int l,int r,int ml,int mr,int A)
{
if (ml <= l && r <= mr)
{
Add[o] += 1LL*A;
pushdown(o,l,r);
return;
}
pushdown(o,l,r);
int mid = (l + r) >> 1;
if (ml <= mid) Modify(o<<1,l,mid,ml,mr,A); else pushdown(o<<1,l,mid);
if (mr > mid) Modify(o<<1|1,mid+1,r,ml,mr,A); else pushdown(o<<1|1,mid+1,r);
c[o] = c[o<<1] + c[o<<1|1];
}
LL query(int o,int l,int r,int ql,int qr)
{
pushdown(o,l,r);
if (ql <= l && r <= qr) return c[o];
int mid = (l + r) >> 1; LL ret = 0;
if (ql <= mid) ret += query(o<<1,l,mid,ql,qr);
if (qr > mid) ret += query(o<<1|1,mid+1,r,ql,qr);
return ret;
}
int Quickfa(int x,int y)
{
for (int now = 0; y; y >>= 1,++now)
if (y&1) x = fa[x][now];
return x;
}
LL Query(int x)
{
LL ret = 0;
for (; x; x = fa[x][0])
if (!Huge[x]) ret += query(1,1,n,dfn[x],dfn[x]);
else
{
ret += query(1,1,n,dfn[x] - pos[x] + 1,dfn[x]);
x = Quickfa(x,pos[x] - 1);
}
return ret;
}
int getint()
{
char ch = getchar();
int ret = 0,A = 1;
while (ch < '0' || '9' < ch)
{
if (ch == '-') A = -1;
ch = getchar();
}
while ('0' <= ch && ch <= '9')
ret = ret*10 + ch - '0',ch = getchar();
return ret*A;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
freopen("test.txt","w",stdout);
#endif
n = getint(); m = getint();
for (int i = 1; i <= n; i++) va[i] = getint();
for (int i = 1; i < n; i++)
{
int x = getint(),y = getint();
v[x].push_back(y);
v[y].push_back(x);
}
Dfs1(1,0); L[1] = 1; Dfs2(1,0); Build(1,1,n);
while (m--)
{
int typ = getint(),x = getint(),a;
if (typ == 1) a = getint(),Modify(1,1,n,dfn[x],dfn[x],a);
else if (typ == 2) a = getint(),Modify(1,1,n,dfn[x],ot[x],a);
else printf("%lld\n",Query(x));
}
return 0;
}