题意:给一棵树,并给定各个点权的值,然后有3种操作:
I C1 C2 K: 把C1与C2的路径上的所有点权值加上K
D C1 C2 K:把C1与C2的路径上的所有点权值减去K
Q C:查询节点编号为C的权值
解题思路:这道题是明显的树链剖分问题,只是这里是点权更新,注意与边权更新的不同,剩下的基本是模板了。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 50010; struct Segment { int l,r,sum,lazy; }tree[maxn<<2]; struct Edge { int to,next; }edge[maxn<<1]; int n,m,p,cnt,num,pre[maxn],A[maxn]; int top[maxn],son[maxn],size[maxn]; int fa[maxn],idx[maxn],dep[maxn]; void addedge(int u,int v) { edge[cnt].to = v; edge[cnt].next = pre[u]; pre[u] = cnt++; } void dfs(int u) { size[u] = 1; son[u] = 0; int tmp = 0; for(int i = pre[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(fa[u] == v) continue; fa[v] = u; dep[v] = dep[u] + 1; dfs(v); size[u] += size[v]; if(size[v] > tmp) { tmp = size[v]; son[u] = v; } } } void build_tree(int u,int tp) { idx[u] = ++num; top[u] = tp; if(son[u] != 0) build_tree(son[u],tp); for(int i = pre[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(fa[u] == v || son[u] == v) continue; build_tree(v,v); } } void build_Segment(int rt,int l,int r) { tree[rt].l = l, tree[rt].r = r; tree[rt].sum = tree[rt].lazy = 0; if(l == r) return; int mid = (l + r) >> 1; build_Segment(rt<<1,l,mid); build_Segment(rt<<1|1,mid+1,r); } void PushDown(int rt) { if(tree[rt].lazy != 0) { tree[rt<<1].lazy += tree[rt].lazy; tree[rt<<1].sum += tree[rt].lazy; tree[rt<<1|1].lazy += tree[rt].lazy; tree[rt<<1|1].sum += tree[rt].lazy; tree[rt].lazy = 0; } } void PushUp(int rt) { tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum; } void update(int rt,int l,int r,int val) { if(l <= tree[rt].l && tree[rt].r <= r) { tree[rt].sum += val; tree[rt].lazy += val; return; } PushDown(rt); int mid = (tree[rt].l + tree[rt].r) >> 1; if(l <= mid) update(rt<<1,l,r,val); if(mid < r) update(rt<<1|1,l,r,val); PushUp(rt); } int query(int rt,int pos) { if(tree[rt].l == tree[rt].r) return tree[rt].sum; PushDown(rt); int mid = (tree[rt].l + tree[rt].r) >> 1; if(pos <= mid) return query(rt<<1,pos); else return query(rt<<1|1,pos); } void Modify(int a,int b,int val) { int f1 = top[a], f2 = top[b]; while(f1 != f2) { if(dep[f1] < dep[f2]) { swap(f1,f2); swap(a,b); } update(1,idx[f1],idx[a],val); a = fa[f1], f1 = top[a]; } if(dep[a] > dep[b]) swap(a,b); update(1,idx[a],idx[b],val); } int main() { int u,v,val; char op[2]; while(scanf("%d%d%d",&n,&m,&p)!=EOF) { memset(pre,-1,sizeof(pre)); cnt = num = 0; dep[1] = 0; for(int i = 1; i <= n; i++) scanf("%d",&A[i]); for(int i = 1; i <= m; i++) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } dfs(1); build_tree(1,1); build_Segment(1,1,num); for(int i = 1; i <= n; i++) update(1,idx[i],idx[i],A[i]); while(p--) { getchar(); scanf("%s",op); if(op[0] == 'I') { scanf("%d%d%d",&u,&v,&val); Modify(u,v,val); } else if(op[0] == 'D') { scanf("%d%d%d",&u,&v,&val); Modify(u,v,-val); } else { scanf("%d",&u); printf("%d\n",query(1,idx[u])); } } } return 0; }