Live2D

Query On A Tree 17 题解

link

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\) 中的不在 \(1\to x\) 的链上的节点也是同理。

那我们就可以考虑通过倍增找到答案节点,就是深度最大的最后一个子树大小 \(>\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;
}
posted @ 2022-04-12 22:58  Dark_Romance  阅读(93)  评论(0编辑  收藏  举报