noip模擬15

ccjjxx發表於2024-11-17

A 暴力操作(opt)

B 異或連通(xor)

C 詭異鍵盤(keyboard)

D 民主投票(election)

這道題很簡單。。。

首先,對於一個節點 \(u\),如果 \(siz[u]-1\) 大於了其他所有節點能得到的最大值,那麼它一定能勝利。

那考慮怎麼找到一個值,滿足所有節點能得到的最大值最小?用二分答案即可。

對於一次 check,我們需要一個樹形 dp 去計算當前節點在最大值為 \(mid\) 下溢位的票數。\(dp[u]+=dp[v]+1\)

然後,會有三種情況。

  • 對於 \(siz[u]>res\),一定能勝利;

  • 對於 \(siz[u]<res\),一定不能勝利;

  • 對於 \(siz[u]=res\),如果這個點只有一個,那麼它可以戰勝。否則,若有多個,一定會有幾個相等的。那麼我們用 \(res-1\) 再跑一個 \(dp\),如果節點 \(1\) 的值是 \(1\),就代表有一個節點溢位,並且沿著到根節點的路徑一路溢位到根。那隻需要再次 dfs,找到那個節點就好了,這個節點一定可以戰勝。

然後就是常數問題了。鏈式前向星的常數小於 vector。

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int T,n;
inline int read()
{
	register int s=0;
	register char c=getchar();
	while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9')s=(s<<1)+(s<<3)+(c^48),c=getchar();
	return s;
}
void write(int x)
{
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
struct node{
	int to,next;
}e[N<<1];
namespace q{
	int *siz,*f;
	int head[N],cnt;
	inline void add(int u,int v)
	{
		e[++cnt].to=v,e[cnt].next=head[u];
		head[u]=cnt;
	}
	inline void dfs1(int u)
	{
		siz[u]=1;
		#pragma GCC unroll 2
		for(int i=head[u];i;i=e[i].next)
		{
			int v=e[i].to;
			dfs1(v);siz[u]+=siz[v];
//			if(siz[v]>siz[Son[u]]) Son[u]=v;
		}
	}
	inline void ddfs(int u,int mx)
	{
		f[u]=0;
		#pragma GCC unroll 2
		for(int i=head[u];i;i=e[i].next)
		{
			int v=e[i].to;
			ddfs(v,mx);
			f[u]+=f[v]+1;
		}
		if(f[u]>mx) f[u]-=mx;
		else f[u]=0;
	}
	bitset<N>ans;
	bool fdf=0;
	inline void dddfs(int u,int V){
		if(f[u]&&siz[u]-1==V){
			ans[u]=1;
			fdf=1;
			return ;
		}
		if(fdf)return ;
		#pragma GCC unroll 2
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;
			if(fdf)return ;
			if(f[v])dddfs(v,V);
		}
	}
	void work()
	{
		n=read();
		f=new int [n+2],siz=new int [n+2];
		cnt=0;
		#pragma GCC unroll 32
		for(int i=1;i<=n;i++)head[i]=0;
		#pragma GCC unroll 32
		for(int i=2;i<=n;i++)
		{
			int f=read();
			add(f,i);
		}
		dfs1(1);
		int l=1,r=n,res=0;
		while(l<=r)
		{
			int mid=(l+r)>>1;
			ddfs(1,mid);
			if(f[1]==0) res=mid,r=mid-1;
			else l=mid+1;
		}
		ans.reset();
		#pragma GCC unroll 2
		for(int i=1;i<=n;i++)
		{
			if(siz[i]-1>res) ans[i]=1;
		}
		ddfs(1,res-1);
		if(f[1]==1) 
		{
			fdf=0;
			dddfs(1,res);
		}
		for(int i=1;i<=n;i++) write((int)ans[i]);
		putchar(10);
		delete []siz,delete []f;
	}
}
signed main()
{
//	freopen("2.in","r",stdin);
//	freopen("ans.txt","w",stdout);
	freopen("election.in","r",stdin);
	freopen("election.out","w",stdout);
	T=read();
	while(T--) q::work();
	return 0;
}