看来以后树链剖分要用这个模板了。具体效果怎么样,还要看看,机场wifi太TM慢了。
寒假估计要是有史以来最辛苦的了。寒假疯狂AC万岁。
//树链剖分模板 /* 记siz[v]表示以v为根的子树的节点数,dep[v]表示v的深度(根深度为1),top[v]表示v所在的链的顶端节点,fa[v]表示v的父亲, son[v]表示与v在同一重链上的v的儿子节点(姑且称为重儿子),w[v]表示v与其父亲节点的连边(姑且称为v的父边)在线段树中的位置。 只要把这些东西求出来,就能用logn的时间完成原问题中的操作。 重儿子:siz[u]为v的子节点中siz值最大的,那么u就是v的重儿子。 轻儿子:v的其它子节点。 重边:点v与其重儿子的连边。 轻边:点v与其轻儿子的连边。 重链:由重边连成的路径。 轻链:轻边。 剖分后的树有如下性质: 性质1:如果(v,u)为轻边,则siz[u] * 2 < siz[v]; 性质2:从根到某一点的路径上轻链、重链的个数都不大于logn。 */ //spoj 375 树链剖分 #include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> #define maxn 100000 using namespace std; struct Tree { int l, r, _max; }tree[maxn*4]; struct Eage { int to, next; }eage[maxn*4]; int son[maxn], fa[maxn], top[maxn], six[maxn],e[maxn],w[maxn],dep[maxn],si[maxn][4]; //son:the son in the same hign chain;fa:the father of node;ro:the first of the chain; //w:the number of the chain between the fanther and it;si:used to remember the information of the eage. int n,cnt,z; void add(int a, int b, int c) { eage[++cnt].to = b; eage[cnt].next = e[a]; e[a] = cnt; } void build_tree(int a, int b) //用来给每个边进行编号(重边要连续),并且确定每个点的祖先节点。 { w[a] = ++z; top[a] = b; if (son[a] != 0) build_tree(son[a], b); for (int i = e[a];i != -1;i = eage[i].next) if (eage[i].to != son[a] && eage[i].to != fa[a]) build_tree(eage[i].to, eage[i].to); } void dfs(int v) { six[v] = 1;son[v] = 0; for (int i = e[v];i != -1;i = eage[i].next) { if (eage[i].to == fa[v]) continue; fa[eage[i].to] = v; dep[eage[i].to] = dep[v] + 1; dfs(eage[i].to); if (six[eage[i].to] > six[son[v]]) son[v] = eage[i].to; six[v] += six[eage[i].to]; } } void update(int a, int l, int r, int m, int v) //对树链进行编号后的线段树进行初始化 { if (l == r) { tree[a]._max = v; return; } int mid = (l + r) / 2; if (m <= mid) update(a * 2, l, mid, m, v); else update(a * 2 + 1, mid + 1, r, m, v); tree[a]._max = max(tree[a * 2]._max, tree[a * 2 + 1]._max); } void init() { for (int i = 1;i <= maxn * 4;i++) tree[i]._max = 0; scanf("%d", &n); cnt = 0; z = 0; int root = (1 + n) / 2; dep[root] =fa[root]= 0; for (int i = 1;i < n;i++) { scanf("%d%d%d", &si[i][0], &si[i][1], &si[i][2]); add(si[i][0], si[i][1], si[i][2]); add(si[i][1], si[i][0], si[i][2]); } dfs(root); build_tree(root, root); for (int i = 1;i < n;i++) { if (dep[si[i][0]]>dep[si[i][1]]) swap(si[i][0], si[i][1]); update(1, 1, z, w[si[i][1]], si[i][2]); } } int maxi(int a, int l, int r, int m, int v) { int ans = 0; if ( m<=l&&r <= v) return tree[a]._max; int mid = (l + r) / 2; if (m <= mid) ans =max(ans, maxi(a * 2, l, mid, m, v)); if (v > mid) ans =max(ans, maxi(a * 2 + 1, mid + 1, r, m, v)); //printf("maxi %d %d %d %d %d ans=%d\n", a, l, r, m, v, ans); return ans; } int query(int a, int b) { int f1 = top[a], f2 = top[b], tmp = 0; while (f1 != f2) { if (dep[f1] < dep[f2]) { swap(f1, f2); swap(a, b); } tmp = max(tmp, maxi(1, 1, z, w[f1], w[a])); a = fa[f1]; f1 = top[a]; } if (a == b) return tmp; if (dep[a] > dep[b]) swap(a, b); return max(tmp, maxi(1, 1, z, w[son[a]], w[b])); } void work() { char ch[20]; scanf("%s", ch); while (ch[0] != 'D') { int a, b; scanf("%d%d", &a, &b); if (ch[0] == 'Q') printf("%d\n", query(a, b)); else update(1, 1, z, w[si[a][1]], b); scanf("%s", ch); } } int main() { int T; //freopen("d:\\in.txt", "r", stdin); //freopen("d:\\inn.txt", "w", stdout); scanf("%d", &T); while (T) { memset(e, -1, sizeof(e)); memset(son, 0, sizeof(son)); memset(top, 0, sizeof(top)); memset(six, 0, sizeof(six)); init(); work(); T--; } return 0; }徒手敲了一个下午,很好