2020 ICPC·小米邀请赛 决赛 M 题 Rikka with Employees 题解

2020 ICPC·小米邀请赛 决赛 M 题 Rikka with Employees

原题链接:牛客

这个构造题实在是太神了!

算法标签:树链剖分,分治

首先题目描述比较欺诈。“放假“可以理解成选择点,然后采访一个员工必须要除了它子树内的点其它全部被选择。

分治经常用来处理这个问题。

这里用到了树链剖分的一个性质:沿着重链剖开,形成的子树一定(leq size/2),也就是最多(log)层递归。

则每次选择重链剖开,然后分治算子树。

代码写起来非常短:

/*
{
######################
#       Author       #
#        Gary        #
#        2021        #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
const int MAXN=100000+20;
int n;
vector<int> g[MAXN];
int siz[MAXN];
void paint(int now){
	printf("+%d",now);
	for(auto it:g[now]) paint(it);
}
void undo(int now){
	rb(i,1,siz[now]){
		printf("-");	
	} 
}
void prework(int now){
	siz[now]=1;
	for(auto it:g[now]) prework(it),siz[now]+=siz[it];
}
void get(int now,vector<int> & smll,vector<int> & hvy_chain){
	printf("=%d+%d",now,now);
	hvy_chain.PB(now); 
	int hvy=-INF;
	for(auto it:g[now]) check_max(hvy,siz[it]);
	for(auto it:g[now]) if(siz[it]==hvy){
		hvy=-it;
	}
	else{
		smll.PB(it);
		paint(it);
	}
	if(!g[now].empty())
	get(-hvy,smll,hvy_chain);
	for(auto it:g[now]) if(it!=-hvy){
		undo(it);
	}
	printf("-");
}
void div(vector<int> v);
void work(int now){
	vector<int> sml,chain;
	get(now,sml,chain);
	for(auto it:chain){
		printf("+%d",it);
	}
	div(sml);
	rb(i,1,chain.size()){
		printf("-");
	}
}
void div(vector<int> v){
	if(v.empty()) return;
	if(v.size()==1){
		work(v[0]);
		return ;
	}
	int totsiz=0;
	mp best=II(INF,INF);
	for(auto it:v) totsiz+=siz[it];
	int tmp=0;
	rep(i,v.size()){
		tmp+=siz[v[i]];
		if(abs(tmp-totsiz/2)<best.FIR){
			best=II(abs(tmp-totsiz/2),i);
		}
	}
	vector<int> l,r;
	rb(i,0,best.SEC) l.PB(v[i]);
	rb(i,best.SEC+1,v.size()-1) r.PB(v[i]);
	for(auto it:l) paint(it);
	div(r);
	for(auto it:l) rep(j,siz[it]) printf("-");
	for(auto it:r) paint(it);
	div(l);
	for(auto it:r) rep(j,siz[it]) printf("-");
}
int main(){
	scanf("%d",&n);
	rb(i,2,n){
		int pi;
		scanf("%d",&pi);
		g[pi].PB(i);
	}
	prework(1);
	work(1);
    printf("!");
	return 0;
}

顺便送大家一个checker来检验自己的程序:

/*
{
######################
#       Author       #
#        Gary        #
#        2021        #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
//    int x=0;
//    char ch=getchar();
//    while(ch<'0'||ch>'9'){
//        ch=getchar();
//    }
//    while(ch>='0'&&ch<='9'){
//        x=(x<<1)+(x<<3)+(ch^48);
//        ch=getchar();
//    }
//    return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
int n;
vector<int> g[100000+20];
bool holi[100000+20];
bool dfs2(int now,int to){
	if(to==now) return 1;
	bool ok=holi[now];
	for(auto it:g[now]){
		ok&=dfs2(it,to);
	}
	return ok;
}
bool dfs1(int now){
	bool ok=!holi[now];
	for(auto it:g[now]){
		ok&=dfs1(it);
	}
	return ok;
}
bool check(int now){
	return dfs1(now)&dfs2(1,now);
}
int main(){
	scanf("%d",&n);
	rb(i,2,n){
		int pi;
		scanf("%d",&pi);
		g[pi].PB(i);
	}
	char c;
	stack<int> sta;
	int z=0;
	while(cin>>c){
		if(c=='!') break;
		++z;
		int a;
		if(c=='+'){
			cin>>a;
			if(holi[a]){
				cout<<"Er1"<<endl;	
				return 0;
			}
			sta.push(a);
			holi[a]=1;
		}
		if(c=='-'){
			if(sta.empty()) {
				cout<<"Er2"<<endl;	
				return 0;
			}
			int now=sta.top();
			holi[now]=0;
			sta.pop();
		}
		if(c=='='){
			cin>>a;
			if(!check(a)){
				cout<<"!"<<a<<endl;
				rb(j,1,n) cout<<holi[j];
				cout<<endl;
				cout<<"Er3"<<endl;	
				return 0;
			}
		}
	}
	cout<<z<<endl;
	cout<<"Ac"<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/gary-2005/p/14292925.html