Query On A Tree 17 題解
阿新 • • 發佈:2022-04-12
Solution
不妨設 \(S\) 為總權值。
有一個結論是:
對於任意 dfs 序,對於第一個字首和 \(\ge \lceil \frac{S}{2} \rceil\) 的點 \(x\),答案一定在 \(1\to x\) 的鏈上。
考慮到我們這樣相當於把原樹分成了兩個連通塊,對於 \(\ge \lceil \frac{S}{2} \rceil\) ,不妨設為 \(A\),另外一個不妨設為 \(B\),那麼對於 \(B\) 中的一個點,如果它是重心,那麼它父親一定也是,所以不優(如果點權都 \(\ge 1\) 實際上有 \(B\) 一定不會有重心,但是點權可能為 \(0\))。對於 \(A\)
那我們就可以考慮通過倍增找到答案節點,就是深度最大的最後一個子樹大小 \(>\lfloor\frac{S}{2}\rfloor\)。不難看出的是,這條鏈上的節點的兒子中除了這條鏈上的下一個點,不會有子樹大小 \(> \lfloor\frac{S}{2}\rfloor\) 的。
複雜度 \(\Theta(n\log^2n)\)。
Code
#include <bits/stdc++.h> using namespace std; #define Int register int #define int long long #define MAXN 100005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} template <typename T> inline void chkmax (T &a,T b){a = max (a,b);} template <typename T> inline void chkmin (T &a,T b){a = min (a,b);} vector <int> g[MAXN]; int n,m,ind,tur[MAXN],dfn[MAXN],dep[MAXN],siz[MAXN],top[MAXN],son[MAXN],par[MAXN][21]; void dfs (int u,int fa){ dep[u] = dep[fa] + 1,siz[u] = 1,par[u][0] = fa; for (Int i = 1;i <= 20;++ i) par[u][i] = par[par[u][i - 1]][i - 1]; for (Int v : g[u]) if (v ^ fa){ dfs (v,u),siz[u] += siz[v]; if (siz[v] > siz[son[u]]) son[u] = v; } } void dfs1 (int u,int Top){ dfn[u] = ++ ind,tur[ind] = u,top[u] = Top; if (son[u]) dfs1 (son[u],Top); for (Int v : g[u]) if (v != par[u][0] && v != son[u]) dfs1 (v,v); } struct Segment{ int sum[MAXN << 2],tag[MAXN << 2]; void pushadd (int x,int v,int l,int r){sum[x] += v * (r - l + 1),tag[x] += v;} void pushdown (int x,int l,int r){ int mid = l + r >> 1; pushadd (x << 1,tag[x],l,mid),pushadd (x << 1 | 1,tag[x],mid + 1,r),tag[x] = 0; } void pushup (int x){sum[x] = sum[x << 1] + sum[x << 1 | 1];} void modify (int x,int l,int r,int ql,int qr,int v){ if (l >= ql && r <= qr) return pushadd (x,v,l,r); int mid = l + r >> 1;pushdown (x,l,r); if (ql <= mid) modify (x << 1,l,mid,ql,qr,v); if (qr > mid) modify (x << 1 | 1,mid + 1,r,ql,qr,v); pushup (x); } int query (int x,int l,int r,int ql,int qr){ if (l >= ql && r <= qr) return sum[x]; int mid = l + r >> 1,res = 0;pushdown (x,l,r); if (ql <= mid) res += query (x << 1,l,mid,ql,qr); if (qr > mid) res += query (x << 1 | 1,mid + 1,r,ql,qr); return res; } int findit (int x,int l,int r,int ned){//找到[l,r]中第一個>=ned的位置 if (l == r) return l; int mid = l + r >> 1;pushdown (x,l,r); if (sum[x << 1] >= ned) return findit (x << 1,l,mid,ned); else return findit (x << 1 | 1,mid + 1,r,ned - sum[x << 1]); } }tree; void Tree_Change (int u,int v){ while (top[u] ^ top[v]){ if (dep[top[u]] < dep[top[v]]) swap (u,v); tree.modify (1,1,n,dfn[top[u]],dfn[u],1),u = par[top[u]][0]; } if (dfn[u] > dfn[v]) swap (u,v); tree.modify (1,1,n,dfn[u],dfn[v],1); } void Tree_Modify (int u){ tree.modify (1,1,n,dfn[u],dfn[u] + siz[u] - 1,1); } int Queryit (){ int Sum = tree.sum[1],u = tur[tree.findit (1,1,n,Sum + 1 >> 1)]; for (Int i = 20;~i;-- i){ int v = par[u][i]; if (v && tree.query (1,1,n,dfn[v],dfn[v] + siz[v] - 1) <= Sum / 2) u = par[v][0]; } if (par[u][0] && tree.query (1,1,n,dfn[u],dfn[u] + siz[u] - 1) <= Sum / 2) u = par[u][0]; return u; } signed main(){ read (n); for (Int i = 2,u,v;i <= n;++ i) read (u,v),g[u].push_back (v),g[v].push_back (u); dfs (1,0),dfs1 (1,1); read (m); while (m --> 0){ int opt,u,v;read (opt,u); if (opt == 1) Tree_Modify (u); else read (v),Tree_Change (u,v); write (Queryit ()),putchar ('\n'); } return 0; }