Codeforces 1039D You Are Given a Tree [根号分治,整体二分,贪心]

洛谷

Codeforces


根号分治真是妙啊。


思路

考虑对于单独的一个\(k\)如何计算答案。

与“赛道修建”非常相似,但那题要求边,这题要求点,所以更加简单。

在每一个点贪心地把子树升上来的两条最长的链拼在一起,能组就组,否则把最长链往上送,复杂度\(O(n)\)

那么多个\(k\)怎么办呢?

分析一波,\(k<\sqrt{n}\)时可以暴力计算,而\(k>\sqrt{n}\)\(ans_k\leq \lfloor \frac{n}{k}\rfloor\),只有\(\sqrt{n}​\)种取值。

显然\(ans\)单调不增,所以可以二分边界,复杂度\(O(n\sqrt{n}\log n)\)

把界限调为\(\sqrt{n\log n}\)后复杂度可以优化至\(O(n\sqrt{n\log n})\)

然而我这么写T掉了……

发现网上还有一种整体二分的写法,不知为何跑的飞快……只能改成整体二分了……


代码

注释掉的是根号分治的代码,求找错\(Q\omega Q\)

#include<bits/stdc++.h>
namespace my_std{
	using namespace std;
	#define pii pair<int,int>
	#define fir first
	#define sec second
	#define MP make_pair
	#define rep(i,x,y) for (int i=(x);i<=(y);i++)
	#define drep(i,x,y) for (int i=(x);i>=(y);i--)
	#define go(x) for (int i=head[x];i;i=edge[i].nxt)
	#define sz 101010
	typedef long long ll;
	typedef double db;
	mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
	template<typename T>inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
	template<typename T>inline void read(T& t)
	{
		t=0;char f=0,ch=getchar();double d=0.1;
		while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
		while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
		if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
		t=(f?-t:t);
	}
	template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
	void file()
	{
		#ifndef ONLINE_JUDGE
		freopen("a.txt","r",stdin);
		#endif
	}
//	inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;

int n;
struct hh{int t,nxt;}edge[sz<<1];
int head[sz],ecnt;
void make_edge(int f,int t)
{
	edge[++ecnt]=(hh){t,head[f]};
	head[f]=ecnt;
	edge[++ecnt]=(hh){f,head[t]};
	head[t]=ecnt;
}

int K;
int f[sz];
int id[sz],fa[sz],cnt;
#define v edge[i].t
void dfs(int x,int fa)
{
	::fa[x]=fa;
	go(x) if (v!=fa) dfs(v,x);
	id[++cnt]=x;
}
int check(int len)
{
	K=len;
	int ret=0;
	rep(i,1,n)
	{
		int x=id[i],mx1=0,mx2=0;
		go(x) if (v!=fa[x])
		{
			if (f[v]>mx1) mx2=mx1,mx1=f[v];
			else if (f[v]>mx2) mx2=f[v];
		}
		if (mx1+mx2+1>=K) ++ret,f[x]=0;
		else f[x]=mx1+1;
	}
	return ret;
}
#undef v

int ans[sz];

void solve(int l,int r,int L,int R)
{
	if (r<l) return;
	if (L==R) { rep(i,l,r) ans[i]=L; return; }
	int mid=(l+r)>>1,s=check(mid);
	ans[mid]=s;
	solve(l,mid-1,s,R),solve(mid+1,r,L,s);
}

int main()
{
	file();
	read(n);
	int x,y;
	rep(i,1,n-1) read(x,y),make_edge(x,y);
	dfs(1,0);
	/*
	int T=sqrt(n*log2(n));
	rep(i,1,T) ans[i]=check(i);
	int las=T;
	drep(i,n/T,0)
	{
		int l=las+1,r=n,R=-1;
		while (l<=r)
		{
			int mid=(l+r)>>1;
			if (check(mid)>=i) R=mid,l=mid+1;
			else r=mid-1;
		}
		rep(j,las+1,R) ans[j]=i;
		las=max(las,R);
	}
	rep(i,1,n) printf("%d\n",ans[i]);
	*/
	solve(1,n,0,n);
	rep(i,1,n) printf("%d\n",ans[i]);
	return 0;
}
posted @ 2019-02-12 17:01  p_b_p_b  阅读(504)  评论(0)    收藏  举报