标签:else www. etc air ++ ref cpp ack targe
题目链接 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; }
HDU 5893 List wants to travel(树链剖分+线段树)
标签:else www. etc air ++ ref cpp ack targe
原文地址:http://www.cnblogs.com/cxhscst2/p/7532940.html