CF516D Drazil and Morning Exercise 题解

安利\(:\) 杂题选做

题目链接-Codeforces


不难发现权值分布组成了一棵以\(f_x\)最小的\(x\)为根的树\(,\)其中父亲的权值一定\(\leq\)儿子的权值\(.\)

那么直接\(two-pointers,\)然后用并查集维护当前的答案就可以做到 \(O(nα(n))\)处理一组询问 \(.\)

\(two-pointers\)的细节大概是\(,\)考虑\(l,r\)的移动\(,\) 不难发现\(r\)变小是不会影响联通情况的\(,\)所以就从大往小扫\(.\)

复杂度 \(O(qnα(n)).\)

代码 \(:\)

#include <bits/stdc++.h>
#define LL long long
using namespace std;
template <typename T> void read(T &x){
	x = 0; int f = 1; char ch = getchar();
	while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
	while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();}
	x *= f;
}
inline void write(int x){if (x > 9) write(x/10); putchar(x%10+'0'); }

const int N = 100050;
int To[N<<1],Ne[N<<1],Dis[N<<1],He[N],_;
inline void add(int x,int y,int w){
	++_; To[_] = y,Ne[_] = He[x],Dis[_] = w,He[x] = _;
	++_; To[_] = x,Ne[_] = He[y],Dis[_] = w,He[y] = _;
}
int n; LL a[N]; int p[N],fa[N],dpt[N]; vector<int>ch[N];
inline bool cmp(int x,int y){ return (a[x] != a[y]) ? (a[x] > a[y]) : (dpt[x] > dpt[y]); }

struct DS{
	int cnt[N],ans,fa[N],size[N];
	inline void init(){ memset(cnt,0,(n+1)<<2),ans = 0; for (int i = 1; i <= n; ++i) fa[i] = i,size[i] = 1,++cnt[1]; }
	inline int Find(int x){ return x == fa[x] ? x : (fa[x] = Find(fa[x])); }
	inline void Merge(int x,int y){
		x = Find(x),y = Find(y); if (x == y) return;
		if (size[x] > size[y]) swap(x,y);
		--cnt[size[x]],--cnt[size[y]]; size[y] += size[x]; ++cnt[size[y]];
		ans = max(ans,size[y]);
		fa[x] = y;
	}
	inline void Dec(int x){
		x = Find(x); --cnt[size[x]];
		if (size[x] == ans && !cnt[size[x]]) --ans;
		--size[x]; ++cnt[size[x]];
	}
	inline int Ans(){ return ans; }
}T;

namespace subtask1{
	LL dis[N];
	inline void dfs(int x,int f){ if (f == -1) dis[x] = 0; for (int y,p = He[x]; p ; p = Ne[p]) if ((y=To[p])^f) dis[y] = dis[x] + Dis[p],dfs(y,x); }
	inline void solve(){
		int i,mx,x,y;
		dfs(1,-1); for (mx = 1,i = 2; i <= n; ++i) if (dis[i] > dis[mx]) mx = i;
		x = mx,dfs(x,-1); for (mx = 1,i = 2; i <= n; ++i) if (dis[i] > dis[mx]) mx = i; y = mx;
		for (i = 1; i <= n; ++i) a[i] = dis[i];
		dfs(y,-1); for (i = 1; i <= n; ++i) a[i] = max(a[i],dis[i]);
	}
}

inline void dfs(int x){
	dpt[x] = dpt[fa[x]]+1;
	for (int y,p = He[x]; p ; p = Ne[p]) if ((y=To[p])^fa[x]) fa[y] = x,dfs(y),ch[x].push_back(y);
}

inline int solve(LL d){
	int ans = 1,l,r,x,i;
	T.init();
	for (l = r = 1; l <= n; ++l){
		while (r < n && a[p[l]]-a[p[r+1]] <= d){
			++r; x = p[r];
			for (i = 0; i < ch[x].size(); ++i) T.Merge(x,ch[x][i]);
		}
		ans = max(ans,T.Ans());
		T.Dec(p[l]);
	}
	return ans;
}

int main(){
	int i,x,y,z,Rt;
	read(n);
	for (i = 1; i < n; ++i) read(x),read(y),read(z),add(x,y,z);
	subtask1::solve();
	for (Rt = 1,i = 2; i <= n; ++i) if (a[i] < a[Rt]) Rt = i;
	dfs(Rt);
	for (i = 1; i <= n; ++i) p[i] = i;
	sort(p+1,p+n+1,cmp);
	int q; LL v;
	read(q); while (q--) read(v),write(solve(v)),putchar('\n');
	return 0;
}
posted @ 2020-08-29 10:57  srf  阅读(113)  评论(0编辑  收藏  举报