HDU 3966 Aragorn's Story
先把树剖成链,然后用树状数组维护:
讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇...
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> #include <time.h> using namespace std; const int MAXN = 50010; struct Edge { int to,next; }edge[MAXN*2]; int head[MAXN],tot; int top[MAXN]; int fa[MAXN]; int deep[MAXN]; int num[MAXN]; int p[MAXN]; int fp[MAXN]; int son[MAXN]; int pos; void init() { tot = 0; memset(head,-1,sizeof(head)); pos = 1;//使用树状数组,编号从头1开始 memset(son,-1,sizeof(son)); } void addedge(int u,int v) { edge[tot].to = v; edge[tot].next = head[u]; head[u] = tot++; } void dfs1(int u,int pre,int d) { deep[u] = d; fa[u] = pre; num[u] = 1; for(int i = head[u];i != -1; i = edge[i].next) { int v = edge[i].to; if(v != pre) { dfs1(v,u,d+1); num[u] += num[v]; if(son[u] == -1 || num[v] > num[son[u]]) son[u] = v; } } } void getpos(int u,int sp) { top[u] = sp; p[u] = pos++; fp[p[u]] = u; if(son[u] == -1) return; getpos(son[u],sp); for(int i = head[u];i != -1;i = edge[i].next) { int v = edge[i].to; if( v != son[u] && v != fa[u]) getpos(v,v); } } //树状数组 int lowbit(int x) { return x&(-x); } int c[MAXN]; int n; int sum(int i) { int s = 0; while(i > 0) { s += c[i]; i -= lowbit(i); } return s; } void add(int i,int val) { while(i <= n) { c[i] += val; i += lowbit(i); } } void Change(int u,int v,int val)//u->v的路径上点的值改变val { int f1 = top[u], f2 = top[v]; int tmp = 0; while(f1 != f2) { if(deep[f1] < deep[f2]) { swap(f1,f2); swap(u,v); } add(p[f1],val); add(p[u]+1,-val); u = fa[f1]; f1 = top[u]; } if(deep[u] > deep[v]) swap(u,v); add(p[u],val); add(p[v]+1,-val); } int a[MAXN]; int main() { int M,P; while(scanf("%d%d%d",&n,&M,&P) == 3) { int u,v; int C1,C2,K; char op[10]; init(); for(int i = 1;i <= n;i++) { scanf("%d",&a[i]); } while(M--) { scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } dfs1(1,0,0); getpos(1,1); memset(c,0,sizeof(c)); for(int i = 1;i <= n;i++) { add(p[i],a[i]); add(p[i]+1,-a[i]); } while(P--) { scanf("%s",op); if(op[0] == 'Q') { scanf("%d",&u); printf("%d\n",sum(p[u])); } else { scanf("%d%d%d",&C1,&C2,&K); if(op[0] == 'D') K = -K; Change(C1,C2,K); } } } return 0; }
或者用线段树维护:
要注意,点权的时候,update函数里是不能 if (u == v) return;的。T_T
// HDU 3966 #include <stdio.h> #include <string.h> #include <iostream> #define maxn 50010 #include <vector> using namespace std; int a[maxn]; vector<int> edge[maxn]; int pos; int top[maxn]; int fa[maxn]; int deep[maxn]; int num[maxn]; int p[maxn]; int fp[maxn]; int son[maxn]; //树链剖分 void dfs1(int u, int pre, int d) { // fa num deep deep[u] = d; fa[u] = pre; num[u] = 1; for (int i=0; i<edge[u].size(); ++i) { int v = edge[u][i]; if (v != pre) { dfs1(v, u, d+1); num[u] += num[v]; if (son[u] == -1 || num[v] > num[son[u]]) { son[u] = v; } } } } void dfs2(int u, int sp) { top[u] = sp; p[u] = pos++; fp[p[u]] = u; if (son[u] == -1) return; dfs2(son[u], sp); for (int i=0; i<edge[u].size(); ++i) { int v = edge[u][i]; if (v != son[u] && v != fa[u]) dfs2(v, v); } } //线段树 struct Node { int l, r; int val; int mark; }segTree[maxn*3]; void build(int rt, int l, int r) { segTree[rt].l = l; segTree[rt].r = r; segTree[rt].mark = 0; segTree[rt].val = 0; if (l == r) { segTree[rt].val = a[fp[l] - 1]; return; } int mid = (l + r) / 2; build(rt<<1, l, mid); build((rt<<1)|1, mid+1, r); } void push_down(int rt) { if (segTree[rt].mark != 0) { segTree[rt].val += segTree[rt].mark; if (segTree[rt].l != segTree[rt].r) { segTree[rt<<1].mark += segTree[rt].mark; segTree[(rt<<1)|1].mark += segTree[rt].mark; } segTree[rt].mark = 0; } } void update_seg(int rt, int l, int r, int val) { // 把线段树的[l, r] 区间的值+val push_down(rt); if (segTree[rt].l >= l && segTree[rt].r <= r) { segTree[rt].mark += val; push_down(rt); return; } int mid = (segTree[rt].l + segTree[rt].r) / 2; if (r <= mid) update_seg(rt<<1, l, r, val); else if (l > mid) update_seg((rt<<1)|1, l, r, val); else { update_seg(rt<<1, l, mid, val); update_seg((rt<<1)|1, mid+1, r, val); } } void update(int u, int v, int w) { // u 到 v结点的路上的值增加 val int f1 = top[u]; int f2 = top[v]; while(f1 != f2) { if (deep[f1] < deep[f2]) { swap(f1, f2); swap(u, v); } update_seg(1, p[f1], p[u], w); u = fa[f1], f1 = top[u]; } // if (u == v) return; if (deep[u] > deep[v]) swap(u, v); update_seg(1, p[u], p[v], w); } int query_seg(int rt, int los) { //查询线段树 los处的值 push_down(rt); if (segTree[rt].l == segTree[rt].r && segTree[rt].r == los) { return segTree[rt].val; } int mid = (segTree[rt].l + segTree[rt].r) / 2; if (los <= mid) return query_seg(rt<<1, los); else if (los > mid) return query_seg((rt<<1)|1, los); } int query(int u) { // 询问u点处的值 return query_seg(1, p[u]); } int n; void init() { pos = 0; memset(son, -1, sizeof(son)); for (int i=1; i<=n; ++i) { edge[i].clear(); } } int main() { // freopen("in.cpp", "r", stdin); int m, pp; while(~scanf("%d%d%d", &n, &m, &pp)) { init(); for (int i=0; i<n; ++i) { scanf("%d", &a[i]); } for (int i=0; i<m; ++i) { int a, b; scanf("%d%d", &a, &b); edge[a].push_back(b); edge[b].push_back(a); } dfs1(1, 0, 1); dfs2(1, 1); build(1, 0, pos-1); for (int i=0; i<pp; ++i) { char op[10]; int u, v, w; scanf("%s", op); if (op[0] == 'I' || op[0] == 'D') { scanf("%d%d%d", &u, &v, &w); if (op[0] == 'D') w = -w; update(u, v, w); }else { scanf("%d", &u); int ans = query(u); printf("%d\n", ans); } } } return 0; }