Attention
When seeking subtrees, the sub-tree DFS sequence is used consecutively, but not in the following way (sub represents the largest DFS order in the subtree of x):
void dfs2(int x, int t) { top[x] = t; dfn[x] = ++cnt; subcnt = max(subcnt, cnt); rnk[cnt] = x; sub[x] = cnt; if(!son[x]) return; dfs2(son[x], t); for(int i=last[x]; i; i=e[i].to) { int v = e[i].v; if(v != son[x] && v != fa[x]) { dfs2(v, v); } } sub[x] = subcnt;}
Because this will not handle the leaf node (directly returned)
The best way to do this is to figure it out with size.
dfn[x] + siz[x] - 1
More details, all in the comments.
Repetition of variable names is really scary ... I haven't seen it in a while.
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio>using namespace STD; #define DEBUG (x) cerr << #x << "=" << x << endl;const int maxn = 100000 + 10;const int maxm = 2 * maxn;int N,m,ans,vis[maxn],edge_tot,r,p,dep[maxn],son[maxn],top[maxn],dfn[maxn],fa[maxn];int siz[MAXN],rnk[ maxn],cnt,sub[maxn],subcnt,last[maxn],a[maxn];struct edge{int u,v,to; Edge () {} edge (int u, int v, int to): U (U), V (v), to (to) {}}e[maxm];inline void Add (int u, int v) {E[++edge_tot] = Edge (U, V, last[u]); Last[u] = Edge_tot;} struct segment{int siz,sum,add;} TR[MAXN * 4];void Down (int. now) {tr[now*2].sum + = Tr[now*2].siz * TR[NOW].ADD; Tr[now*2+1].sum + = Tr[now*2+1].siz * TR[NOW].ADD; Tr[now*2].sum%= p; Tr[now*2+1].sum%= p; Tr[now*2].add + = Tr[now].add; Tr[now*2+1].add + = Tr[now].add; Tr[now].add = 0;} void Update (int pos) {tr[pos].siz = Tr[pos*2].siz + tr[pos*2+1].siz; Tr[pos].sum = tr[pos*2].suM + tr[pos*2+1].sum; Tr[pos].sum%= p;} void build_segment (int now, int l, int r) {if (L = = r) {tr[now].siz = 1; Tr[now].sum = a[rnk[l]];//The number of the corresponding point of the DFS order, then its value, here is not a[l], is the corresponding point number return; } int mid = l+r>>1; Build_segment (Now*2, L, mid); Build_segment (Now*2+1, mid+1, R); Update (now);} void Change (int. now, int l, int r, int x, int y, int k) {if (x <= l && r <= y) {tr[now].add + = k; Tr[now].sum + = Tr[now].siz * k; Tr[now].sum%= p; Return } down (now); int mid = l+r>>1; if (x <= mid)//with no left son to go, just look for the change border changes (Now*2, L, Mid, X, Y, k); if (Y > Mid) Change (now*2+1, mid+1, R, X, y, k); Update (now);} int query (int now, int l, int r, int x, int y) {if (x <= l && r <= y) {return tr[now].sum% P; } down (now); A long long sum = 0; int mid = l+r>>1; if (x <= mid) sum + = query (Now*2, L, Mid, X, y); if (Y > mid) Sum + = Query (now*2+1, mid+1, R, X, y); Sum%= p; return sum;} void dfs1 (int x, int f, int depth) {fa[x] = f; DEP[X] = depth; SIZ[X] = 1; for (int i=last[x]; i; i=e[i].to) {int v = E[I].V; if (v = = f) continue;//is executed continue instead of v!=f, because that would be to increase the parentheses ... DFS1 (V, x, depth + 1); SIZ[X] + = Siz[v]; if (Siz[v] > Siz[son[x]]) {son[x] = V; }}}void DFS2 (int x, int t) {top[x] = t; DFN[X] = ++cnt; RNK[CNT] = x; if (!son[x]) return; DFS2 (Son[x], t);//Ensure that the points on the heavy chain DFS sequential for (int i=last[x]; i; i=e[i].to) {int v = E[I].V; if (v = son[x] && v! = fa[x]) {DFS2 (V, v); }}}int path_query (int x, int y) {long long sum = 0; while (top[x]! = Top[y]) {if (Dep[top[x]] < dep[top[y]) swap (x, y);//Let X go deeper, so jump x sum + = query (1, 1, N, DFN [Top[x]], dfn[x]);//Be sure to write topx instead of tx = TOPX because XY will swap, the advance setting will be messed up ... Sum%= p; x = fa[top[x]]; } if (Dfn[x] > Dfn[y]) Swap (x, y); Sum + = Query (1, 1, N, Dfn[x], dfn[y]); Sum%= p; return sum;} void path_update (int x, int y, int k) {while (top[x]! = Top[y]) {if (Dep[top[x] < dep[top[y]]) swap (x, y); Change (1, 1, N, Dfn[top[x]], dfn[x], k); x = fa[top[x]]; } if (Dfn[x] > Dfn[y]) swap (x, y); Change (1, 1, N, Dfn[x], Dfn[y], k);} int main () {scanf ("%d%d%d%d", &n, &m, &r, &p); for (int i=1; i<=n; i++) {scanf ("%d", &a[i]); } for (int i=1; i<n; i++) {int x, y; scanf ("%d%d", &x, &y); Add (x, y); Add (y, x); } dfs1 (r, 0, 1); DFS2 (R,R); Build_segment (1, 1, N); for (int i=1; i<=m; i++) {int cmd,x,y,z; scanf ("%d", &cmd); if (cmd = = 1) {scanf ("%d%d%d", &x, &y, &z); Path_update (x, y, z); } else if (cmd = = 2) {scanf ("%d%d", &x, &y); printf ("%d\n", Path_query (x, y)); } else if(cmd = = 3) {scanf ("%d%d", &x, &y); Change (1, 1, N, Dfn[x], dfn[x] + siz[x]-1, y); } else if (cmd = = 4) {scanf ("%d", &x); printf ("%d\n", Query (1, 1, N, Dfn[x], dfn[x] + siz[x]-1)); }} return 0;}
Two practiced hand questions ... Point modification and Edge modification
Rokua P3128 [usaco15dec] Max flow max flows
, respectively
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include < ctime>using namespace std; #define DEBUG (x) cerr << #x << "=" << x << endl;const int MAXN = 5000 0 + 10;const int maxm = MAXN * 2;int N,k,dep[maxn],fa[maxn],son[maxn],dfn[maxn],top[maxn],rnk[maxn],dfs_seq,edge_tot, last[maxn],siz[maxn];struct edge{int u,v,to; Edge () {} edge (int u, int v, int to): U (U), V (v), to {}}E[MAXM]; inline void Add (int u, int v) {E[++edge_tot] = Edge (U, V, last[u]); Last[u] = Edge_tot;} struct segmenttree{int val, tag;} tr[maxn*4];void (int now) {int tagadd = Tr[now].tag; Tr[now*2].val + = Tagadd; Tr[now*2+1].val + = Tagadd; Tr[now*2].tag + = Tagadd; Tr[now*2+1].tag + = Tagadd; Tr[now].tag = 0;} void Change (int now, int l, int r, int cx, int cy, int k) {if (CX <= l && R <= Cy) {Tr[now].tag + = k; Tr[now].val + = k; Return } down (now); int mid = l+r>>1; if (CX <= mid) Change (Now*2, L, Mid, CX, CY, K); if (Cy > Mid) Change (now*2+1, mid+1, R, CX, CY, K); Tr[now].val = Max (Tr[now*2].val, tr[now*2+1].val);} void dfs1 (int x, int father, int depth) {dep[x] = depth; SIZ[X] = 1; Fa[x] = father; for (int i=last[x]; i; i=e[i].to) {int v = E[I].V; if (v = = father) Continue; DFS1 (V, X, depth+1); SIZ[X] + = Siz[v]; if (Siz[v] > Siz[son[x]]) son[x] = v; }}void DFS2 (int x, int t) {top[x] = t; DFN[X] = ++dfs_seq; RNK[DFS_SEQ] = x; if (!son[x]) return; DFS2 (Son[x], T); for (int i=last[x]; i; i=e[i].to) {int v = E[I].V; if (v = = Fa[x] | | v = = son[x]) continue; DFS2 (V, v); }}int path_change (int x, int y, int k) {while (top[x]! = Top[y]) {if (Dep[top[x]] < Dep[top[y]]) swap (x, y); Change (1, 1, N, Dfn[top[x]], dfn[x], k); x = fa[top[x]]; } if (Dfn[x] > Dfn[y]) swap (x, y); Change (1,1, N, Dfn[x], Dfn[y], k);} int main () {scanf ("%d%d", &n, &k); for (int i=1; i<n; i++) {int u,v; scanf ("%d%d", &u, &v); Add (U, v); Add (V, u); } dfs1 (1, 0, 1); DFS2 (1, 1); for (int i=1; i<=k; i++) {int S, t; scanf ("%d%d", &s, &t); Path_change (S, T, 1); } printf ("%d", tr[1].val); return 0;}
Rokua P3038 [usaco11dec] pasture planting grass planting
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include < ctime>using namespace std; #define DEBUG (x) cerr << #x << "=" << x << endl;const int MAXN = 1000 xx + 10;const int maxm = MAXN * 2;int N,m,dep[maxn],fa[maxn],son[maxn],dfn[maxn],top[maxn],rnk[maxn],dfs_seq,edge_tot, last[maxn],siz[maxn];struct edge{int u,v,to; Edge () {} edge (int u, int v, int to): U (U), V (v), to {}}E[MAXM]; inline void Add (int u, int v) {E[++edge_tot] = Edge (U, V, last[u]); Last[u] = Edge_tot;} struct segmenttree{int val, tag;} Tr[maxn*4];void Down (int. now) {Tr[now*2].tag + = Tr[now].tag; Tr[now*2+1].tag + = Tr[now].tag; Tr[now*2].val + = Tr[now].tag; Tr[now*2+1].val + = Tr[now].tag; Tr[now].tag = 0;} void Change (int. now, int l, int r, int x, int y, int k) {if (x <= l && r <= y) {tr[now].tag + = k; Tr[now].val + = k; Return } down (now); int mid = L+r>>1; if (x <= mid) Change (Now*2, L, Mid, X, Y, k); if (Y > Mid) Change (now*2+1, mid+1, R, X, y, k);} int query (int now, int l, int r, int x) {if (L = = r) return tr[now].val; Down (now); int mid = l+r>>1; if (x <= mid) return query (Now*2, L, Mid, X); else return query (now*2+1, mid+1, R, x);} void dfs1 (int x, int father, int depth) {dep[x] = depth; SIZ[X] = 1; Fa[x] = father; for (int i=last[x]; i; i=e[i].to) {int v = E[I].V; if (v = = father) Continue; DFS1 (V, X, depth+1); SIZ[X] + = Siz[v]; if (Siz[v] > Siz[son[x]]) son[x] = v; }}void DFS2 (int x, int t) {top[x] = t; DFN[X] = ++dfs_seq; RNK[DFS_SEQ] = x; if (!son[x]) return; DFS2 (Son[x], T); for (int i=last[x]; i; i=e[i].to) {int v = E[I].V; if (v = = Fa[x] | | v = = son[x]) continue; DFS2 (V, v); }}void path_change (int x, int y, int k) {while (top[x]! = Top[y]) {if (Dep[top[x]] < DEp[top[y]]) swap (x, y); Change (1, 1, N, Dfn[top[x]], dfn[x], k); x = fa[top[x]]; } if (Dfn[x] > Dfn[y]) swap (x, y); Change (1, 1, N, Dfn[x], Dfn[y], k); Change (1, 1, N, Dfn[x], dfn[x],-K); int main () {scanf ("%d%d", &n, &m); for (int i=1; i<n; i++) {int u,v; scanf ("%d%d", &u, &v); Add (U, v); Add (V, u); } dfs1 (1, 0, 1); DFS2 (1, 1); for (int i=1; i<=m; i++) {char cmd; Cin >> cmd; int AI, bi; scanf ("%d%d", &ai, &bi); if (cmd = = ' P ') {path_change (AI, Bi, 1); } else {printf ("%d\n", Query (1, 1, N, Max (Dfn[ai], Dfn[bi])); }} return 0;}
Tree Chain template