HDU 5893 List wants to travel(树链剖分+线段树)
题目链接 HDU5893
$2016$年$ICPC$沈阳网络赛的$B$题。这道题其和 BZOJ2243 基本一样
那道题我也写了题解 点这里
两道题的区别就是$BZOJ$这题是点的权值,这道题是边权。
所以我们把边权看成这条边连接的两个点的深度较大的那条边的点权就可以了。
但是这样的话根结点就没有权值了。
询问和查询的时候,若$x$和$y$的$LCA$为$t$,
那么我们从$x$出发往上爬,爬到$X'$,使得$deep[X'] - deep[t] = 1$
同样我们从$y$出发往上爬,爬到$Y'$,使得$deep[Y'] - deep[t] = 1$
于是一个询问被我们拆成了两个,一个查询也被我们拆成了两个。
然后依次处理就好了。
当$x$是$y$的祖先,或者$y$是$x$的祖先的时候,特判下即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define lson i << 1, L, mid #define rson i << 1 | 1, mid + 1, R #define MP make_pair #define fi first #define se second typedef long long LL; typedef pair<int, int> PII; const int N = 5e4 + 10; const int A = 19; vector <PII> v[N]; int father[N], deep[N], c[N], sz[N], son[N], f[N], top[N]; int lazy[N << 2], s[N << 2], lc[N << 2], rc[N << 2]; int st[N][A]; int n, m, tot; char op[10]; void dfs(int x, int fa, int dep, int val){ sz[x] = 1; father[x] = fa; deep[x] = deep[fa] + 1; c[x] = val; if (fa){ st[x][0] = fa; for (int i = 0; st[st[x][i]][i]; ++i) st[x][i + 1] = st[st[x][i]][i]; } for (auto cnt : v[x]){ int u = cnt.fi, w = cnt.se; if (u == fa) continue; dfs(u, x, dep + 1, w); sz[x] += sz[u]; if (sz[son[x]] < sz[u]) son[x] = u; } } void dfs2(int x, int tp){ f[x] = ++tot; top[x] = tp; if (son[x]) dfs2(son[x], tp); for (auto cnt : v[x]){ int u = cnt.fi, w = cnt.se; if (u == father[x] || u == son[x]) continue; dfs2(u, u); } } int LCA(int x, int y){ for (; top[x] ^ top[y]; ){ if (deep[top[x]] < deep[top[y]]) swap(x, y); x = father[top[x]]; } return deep[x] > deep[y] ? y : x; } inline int updis(int x, int dis){ dec(i, 17, 0) if ((1 << i) & dis) x = st[x][i], dis ^= (1 << i); return x; } inline void pushup(int i){ lc[i] = lc[i << 1]; rc[i] = rc[i << 1 | 1]; if (rc[i << 1] ^ lc[i << 1 | 1]) s[i] = s[i << 1] + s[i << 1 | 1]; else s[i] = s[i << 1] + s[i << 1 | 1] - 1; } inline void pushdown(int i, int L, int R){ int tmp = lazy[i]; if (tmp == -1 || L == R) return; s[i << 1] = s[i << 1 | 1] = 1; lazy[i << 1] = lazy[i << 1 | 1] = tmp; lc[i << 1] = rc[i << 1] = tmp; lc[i << 1 | 1] = rc[i << 1 | 1] = tmp; lazy[i] = -1; } void build(int i, int L, int R){ s[i] = 1; lazy[i] = -1; if (L == R) return; int mid = (L + R) >> 1; build(lson); build(rson); } void change(int i, int L, int R, int l, int r, int val){ pushdown(i, L, R); if (L == l && R == r){ lc[i] = rc[i] = val; s[i] = 1; lazy[i] = val; return; } int mid = (L + R) >> 1; if (r <= mid) change(lson, l, r, val); else if (l > mid) change(rson, l, r, val); else{ change(lson, l, mid, val); change(rson, mid + 1, r, val); } pushup(i); } int query(int i, int L, int R, int l, int r){ pushdown(i, L, R); if (L == l && R == r) return s[i]; int mid = (L + R) >> 1; if (r <= mid) return query(lson, l, r); else if (l > mid) return query(rson, l, r); else{ int tmp = 1; if (rc[i << 1] ^ lc[i << 1 | 1]) tmp = 0; return query(lson, l, mid) + query(rson, mid + 1, r) - tmp; } } int getcolor(int i, int L, int R, int x){ pushdown(i, L, R); if (L == R) return lc[i]; int mid = (L + R) >> 1; if (x <= mid) return getcolor(lson, x); else return getcolor(rson, x); } int solvesum(int x, int tp){ int ret = 0; for (; top[x] ^ top[tp] ;){ ret += query(1, 1, n, f[top[x]], f[x]); if (getcolor(1, 1, n, f[top[x]]) == getcolor(1, 1, n, f[father[top[x]]])) --ret; x = father[top[x]]; } ret += query(1, 1, n, f[tp], f[x]); return ret; } void solvechange(int x, int tp, int val){ for (; top[x] ^ top[tp]; ){ change(1, 1, n, f[top[x]], f[x], val); x = father[top[x]]; } change(1, 1, n, f[tp], f[x], val); } int main(){ while (~scanf("%d%d", &n, &m)){ tot = 0; rep(i, 0, n + 1) v[i].clear(); memset(st, 0, sizeof st); memset(f, 0, sizeof f); memset(father, 0, sizeof father); rep(i, 2, n){ int x, y, z; scanf("%d%d%d", &x, &y, &z); v[x].push_back(MP(y, z)); v[y].push_back(MP(x, z)); } memset(son, 0, sizeof son); dfs(1, 0, 1, 0); dfs2(1, 1); memset(lc, 0, sizeof lc); memset(rc, 0, sizeof rc); build(1, 1, n); rep(i, 2, n) change(1, 1, n, f[i], f[i], c[i]); while (m--){ scanf("%s", op); if (op[0] == 'Q'){ int x, y; scanf("%d%d", &x, &y); if (x == y){ puts("0"); continue; } if (deep[x] < deep[y]) swap(x, y); int t = LCA(x, y); if (y == t){ int yy = updis(x, deep[x] - deep[y] - 1); printf("%d\n", solvesum(x, yy)); continue; } int xx = updis(x, deep[x] - deep[t] - 1); int yy = updis(y, deep[y] - deep[t] - 1); int reta = solvesum(x, xx); int retb = solvesum(y, yy); int ret; if (getcolor(1, 1, n, f[xx]) == getcolor(1, 1, n, f[yy])) ret = reta + retb - 1; else ret = reta + retb; printf("%d\n", ret); } else{ int x, y, z; scanf("%d%d%d", &x, &y, &z); if (x == y) continue; if (deep[x] < deep[y]) swap(x, y); int t = LCA(x, y); if (y == t){ int yy = updis(x, deep[x] - deep[y] - 1); solvechange(x, yy, z); continue; } int xx = updis(x, deep[x] - deep[t] - 1); int yy = updis(y, deep[y] - deep[t] - 1); solvechange(x, xx, z); solvechange(y, yy, z); } } } return 0; }