题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966
3 2 5 1 2 3 2 1 2 3 I 1 3 5 Q 2 D 1 2 2 Q 1 Q 3
7 4 8Hint1.The number of enemies may be negative. 2.Huge input, be careful.
题意:
给出每个点的初始值,和给出一些边,连成一颗树;
接着三种操作:
1、Q X:询问X这个点的值;
2、I X Y Z:在点X到点Y的路径上所有的点,都增加Z;
3、D X Y Z:在点X到点Y的路径上所有的点,都减少Z;
代码如下:
#include <cstdio> #include <cstring> #define MAXN 50017 #define maxn 100017 int N, M, Q; int siz[MAXN];//siz[v]表示以v为根的子树的节点数 int dep[MAXN];//dep[v]表示v的深度(根深度为1) int top[MAXN];//top[v]表示v所在的重链的顶端节点 int fa[MAXN];//fa[v]表示v的父亲 int son[MAXN];//son[v]表示与v在同一重链上的v的儿子节点 int w[MAXN];//w[v]表示v与其父亲节点的连边(姑且称为v的父边)在线段树中的位置 int cont; int first[maxn], e, next[maxn], v[maxn]; int a[MAXN], add[MAXN*4], q[MAXN]; void swap_(int &x, int &y) { int t; t = x, x = y, y = t; } void Add(int x, int y) { v[e] = y; next[e] = first[x], first[x] = e++; } void pushdown(int cur) { if(add[cur]) { add[cur << 1] += add[cur]; add[cur << 1 | 1] += add[cur]; add[cur] = 0; } } void prepare()//剖分部分 { int x, rear = 0; q[rear++] = 1; fa[1] = 0; dep[1] = 1;//根深度为1 memset(top,0,sizeof(top)); for(int i = 0; i < rear; i++) { x = q[i]; for(int j = first[x]; j != -1; j = next[j]) { if(v[j] != fa[x]) { fa[v[j]] = x, dep[v[j]] = dep[x] + 1; q[rear++] = v[j]; } } } siz[0] = 0; for(int i = rear-1; i >= 0; i--) { x = q[i]; siz[x] = 1, son[x] = 0; for(int j = first[x]; j != -1; j = next[j]) { if(v[j] != fa[x]) { siz[x] += siz[v[j]]; if(siz[v[j]] > siz[son[x]]) son[x] = v[j]; } } } cont = 0; for(int i = 0; i < rear; i++) { x = q[i]; if(top[x] == 0) { for(int j = x; j != 0; j = son[j]) { top[j] = x, w[j] = ++cont; } } } } void Update(int cur, int x, int y, int s, int t, int v)//线段树部分 { int mid = (x+y) >> 1; int ls = cur << 1; int rs = cur << 1 | 1; if(x >= s && y <= t) { add[cur] += v; return ; } pushdown(cur); if(mid >= s) Update(ls, x, mid, s, t, v); if(mid < t) Update(rs, mid+1, y, s, t, v); } int query(int cur, int x, int y, int k) { int mid = (x+y) >> 1; int ls = cur << 1; int rs = cur << 1 | 1; if(x == y) return add[cur]; pushdown(cur); if( k <= mid) return query(ls, x, mid, k); else return query(rs, mid+1, y, k); } void Deal(int x, int y, int z) { int fx = top[x], fy = top[y]; while(fx != fy) { if(dep[fx] > dep[fy]) { swap_(fx, fy); swap_(x, y); } Update(1, 1, N, w[fy], w[y], z); y = fa[fy], fy = top[y]; } if(dep[x] > dep[y]) { swap_(x, y); } Update(1, 1, N, w[x], w[y], z); } int main() { int x, y, z; while(scanf("%d%d%d",&N,&M,&Q) != EOF) { for(int i = 1; i <= N; i++) { scanf("%d",&a[i]); } e = 0; memset(first,-1,sizeof(first)); for(int i = 0; i < M; i++) { scanf("%d%d",&x,&y); Add(x, y); Add(y, x); } prepare(); memset(add,0,sizeof(add)); for(int i = 1; i <= N; i++) { Update(1, 1, N, w[i], w[i], a[i]); } char op[7]; for(int i = 1; i <= Q; i++) { scanf("%s",op); if(op[0] == 'Q') { scanf("%d",&x); printf("%d\n",query(1, 1, N, w[x])); } else { scanf("%d%d%d",&x,&y, &z); if(op[0] == 'I') Deal(x, y, z); else Deal(x, y, -z); } } } return 0; }
HDU 3966 Aragorn's Story(树链剖分 模板题)
原文地址:http://blog.csdn.net/u012860063/article/details/43311773