題面
Bzoj
Sol
做個轉化
最開始都是虛邊
操作\(1\)就是\(LCT\)里的\(Access\)操作
求的就是路徑上虛邊的個數+1
然后就好辦了
用樹鏈剖分+線段樹來維護每個點到根虛邊的個數的最大值
操作\(1\):\(Access\)時虛實邊的轉換,要把原來連的點的\(Splay\)的最左邊的點在原樹中的子樹所有點+1,再把現在連的點做同樣的操作-1
操作\(2\):單點查詢,記\(deep[x]\)為\(x\)到根的虛邊個數,那么答案就是\(deep[x]+deep[y]-2*deep[lca]+1\)
操作\(3\):子樹最大值
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(2e5 + 5);IL ll Input(){RG ll x = 0, z = 1; RG char c = getchar();for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);return x * z;
}int size[_], Fa[_], deep[_], top[_], son[_], dfn[_], Index, ed[_], id[_];
int fst[_], nxt[_], to[_], cnt, n, m;
int ch[2][_], fa[_];
int mx[_ << 2], tag[_ << 2];IL void Add(RG int u, RG int v){nxt[cnt] = fst[u]; to[cnt] = v; fst[u] = cnt++;
}# define lson x << 1, l, mid
# define rson x << 1 | 1, mid + 1, rIL void Build(RG int x, RG int l, RG int r){if(l == r){mx[x] = deep[id[l]];return;}RG int mid = (l + r) >> 1;Build(lson); Build(rson);mx[x] = max(mx[x << 1], mx[x << 1 | 1]);
}IL void Modify(RG int x, RG int l, RG int r, RG int L, RG int R, RG int v){if(L <= l && R >= r){tag[x] += v, mx[x] += v;return;}RG int mid = (l + r) >> 1;if(L <= mid) Modify(lson, L, R, v);if(R > mid) Modify(rson, L, R, v);mx[x] = max(mx[x << 1], mx[x << 1 | 1]) + tag[x];
}IL int Query(RG int x, RG int l, RG int r, RG int L, RG int R){if(L <= l && R >= r) return mx[x];RG int mid = (l + r) >> 1, ans = 0;if(L <= mid) ans = Query(lson, L, R);if(R > mid) ans = max(ans, Query(rson, L, R));return ans + tag[x];
}# undef lson
# undef rsonIL void Dfs1(RG int u){size[u] = 1;for(RG int e = fst[u]; e != -1; e = nxt[e]){if(size[to[e]]) continue;fa[to[e]] = Fa[to[e]] = u, deep[to[e]] = deep[u] + 1;Dfs1(to[e]);size[u] += size[to[e]];if(size[to[e]] > size[son[u]]) son[u] = to[e];}
}IL void Dfs2(RG int u, RG int Top){dfn[u] = ++Index, top[u] = Top, id[Index] = u;if(son[u]) Dfs2(son[u], Top);for(RG int e = fst[u]; e != -1; e = nxt[e])if(!dfn[to[e]]) Dfs2(to[e], to[e]);ed[u] = Index;
}IL int LCA(RG int u, RG int v){while(top[u] ^ top[v]){if(deep[top[u]] > deep[top[v]]) swap(u, v);v = Fa[top[v]];}return deep[u] > deep[v] ? v : u;
}IL int Son(RG int x){ return ch[1][fa[x]] == x; }IL int Isroot(RG int x){ return ch[0][fa[x]] != x && ch[1][fa[x]] != x; }IL int Find(RG int x){ while(ch[0][x]) x = ch[0][x]; return x; } IL void Rotate(RG int x){RG int y = fa[x], z = fa[y], c = Son(x);if(!Isroot(y)) ch[Son(y)][z] = x; fa[x] = z;ch[c][y] = ch[!c][x]; fa[ch[c][y]] = y;ch[!c][x] = y; fa[y] = x;
}IL void Splay(RG int x){for(RG int y = fa[x]; !Isroot(x); Rotate(x), y = fa[x])if(!Isroot(y)) Son(x) ^ Son(y) ? Rotate(x) : Rotate(y);
}IL void Access(RG int x){for(RG int y = 0, ff; x; y = x, x = fa[x]){Splay(x);if(ch[1][x]) ff = Find(ch[1][x]), Modify(1, 1, n, dfn[ff], ed[ff], 1);if(y) ff = Find(y), Modify(1, 1, n, dfn[ff], ed[ff], -1);ch[1][x] = y;}
}int main(RG int argc, RG char* argv[]){n = Input(); m = Input(); Fill(fst, -1);for(RG int i = 1, x, y; i < n; ++i)x = Input(), y = Input(), Add(x, y), Add(y, x);Dfs1(1), Dfs2(1, 1), Build(1, 1, n);for(RG int i = 1; i <= m; ++i){RG int opt = Input(), x = Input(), y, ans = 0, lca;if(opt == 1) Access(x);else if(opt == 2){y = Input(), lca = LCA(x, y);ans = Query(1, 1, n, dfn[x], dfn[x]) + Query(1, 1, n, dfn[y], dfn[y]);ans -= 2 * Query(1, 1, n, dfn[lca], dfn[lca]);printf("%d\n", ans + 1);}else printf("%d\n", Query(1, 1, n, dfn[x], ed[x]) + 1);}return 0;
}
轉載于:https://www.cnblogs.com/cjoieryl/p/8438227.html
總結
以上是生活随笔為你收集整理的Bzoj4817:[SDOI2017]树点涂色的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。