1. 程式人生 > >牛客NOIP提高組R1 C保護(主席樹)

牛客NOIP提高組R1 C保護(主席樹)

sin inline swap number node oid ima nts info

題意

題目鏈接

技術分享圖片

Sol

Orz lyq

我們可以把一支軍隊(u, v)拆分為兩個(u, lca)和(v, lca) 考慮一個點x,什麽時候軍隊對它有貢獻,肯定是u或v在他的子樹內,且lca在他的子樹外 因為需要讓至少k個軍隊能夠完全覆蓋,所以肯定是選深度第k小的 這個過程可以用dfs序+主席樹來實現 拿(u, lca)來說,在dfn[u]對應的線段樹中,dep[lca]處+1即可。 然後查第k大即可

/**/
#include<cstdio>
#include<vector>
using namespace std;
const int
MAXN = 2 * 1e5 + 10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < 0 || c > 9) {if(c == -) f = -1; c = getchar();} while(c >= 0 && c <= 9) x = x * 10 + c - 0, c = getchar(); return x * f; } int N, M; struct Node { int siz; }T[MAXN
* 70]; int root[MAXN * 70], ls[MAXN * 70], rs[MAXN * 70]; int dep[MAXN], fa[MAXN], top[MAXN], siz[MAXN], son[MAXN], deep[MAXN], dfn[MAXN], cnt, tot, num, ID[MAXN]; vector<int> v[MAXN], Q[MAXN];//Q[i] dfs搴忎負i鐨勯渶瑕佸姞鍏ョ殑鍏冪礌 void dfs1(int x, int _fa) { dfn[x] = ++cnt; fa[x] = _fa; siz[x]= 1
; deep[x] = deep[_fa] + 1; for(int i = 0; i < (int)v[x].size(); i++) { int to = v[x][i]; if(to == _fa) continue; dfs1(to, x); siz[x] += siz[to]; if(siz[to] > siz[son[x]]) son[x] = to; } } void dfs2(int x, int topf) { top[x] = topf; if(!son[x]) return ; dfs2(son[x], topf); for(int i = 0; i < (int)v[x].size(); i++) { int to = v[x][i]; if(top[to]) continue; dfs2(to, to); } } int LCA(int x, int y) { while(top[x] != top[y]) { if(deep[top[x]] < deep[top[y]]) swap(x, y); x = fa[top[x]]; } if(deep[x] > deep[y]) swap(x, y); return x; } void Insert(int &k, int p, int l, int r, int pos) { if(l > r) return ; if(!k) k = ++tot, T[k].siz = T[p].siz + 1; if(l == r) return ; int mid = (l + r) >> 1; if(pos <= mid) rs[k] = rs[p], Insert(ls[k], ls[p], l, mid, pos); else ls[k] = ls[p], Insert(rs[k], rs[p], mid + 1, r, pos); } int Query(int rl, int rr, int k, int l, int r) { if(T[rr].siz - T[rl].siz < k) return 0; if(l == r) return k > (T[rr].siz - T[rl].siz) ? 0 : l; int si = T[ls[rr]].siz - T[ls[rl]].siz; int mid = (l + r) >> 1; if(si >= k) return Query(ls[rl], ls[rr], k, l, mid); else return Query(rs[rl], rs[rr], k - si, mid + 1, r); } int main() { // freopen("a.in", "r", stdin); // freopen("b.out", "w", stdout); N = read(); M = read(); for(int i = 1; i <= N - 1; i++) { int x = read(), y = read(); v[x].push_back(y); v[y].push_back(x); } dfs1(1, 0); dfs2(1, 1); for(int i = 1; i <= M; i++) { int x = read(), y = read(), lca = LCA(x, y); Q[dfn[x]].push_back(deep[lca]); Q[dfn[y]].push_back(deep[lca]); } for(int i = 1; i <= N; i++) { for(int j = 0; j < (int)Q[i].size(); j++) { int x = Q[i][j]; ++num; Insert(root[num], root[num - 1], 1, N, x); } ID[i] = num; } int Q = read(); while(Q--) { int u = read(), k = read(); int ans = Query(root[ID[dfn[u] - 1]], root[ID[dfn[u] + siz[u] - 1]], k, 1, N); if(ans == 0 || (deep[u] - ans <= 0)) printf("0\n"); else printf("%d\n", deep[u] - ans); } return 0; } /**/

牛客NOIP提高組R1 C保護(主席樹)