CF1423N BubbleSquare Tokens

I.CF1423N BubbleSquare Tokens

神仙构造题。

首先,我们令所有点初始都没有放币,所有边上都放了一个币。则此时每个点的权值即为它的度数。

然后,我们考虑从小到大计算每个点的权值。对于每个点(i),我们枚举它所有相邻且编号比它小的点,假如该点上没有币,就把币从连接两点的边上移到另一端的点上。明显这样操作并不会改变该点的权值,只会减少当前点的权值。

这之后,上述所有点上都有了币。则我们可以选择将某些币移回边上,显然这只会单纯增加当前点的权值。假设当前点与(k)个点相邻,则它的权值可以被加上([0,k])中任何一个数(取决于你究竟打算移回多少个币)。而这共(k+1)个值中,最多只有(k)个值被其余点占去,则当前点完全可以占住剩下那一个。直接使用一个哈希表维护有哪些值被占去即可。

时间复杂度(O(klog n))(O(k)),取决于使用哪种哈希表。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,cnt;
bool on[12510];
int sum[12510];
int val[1001000],s[1001000],t[1001000];
vector<int>v[12510];
set<int>hs;
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)scanf("%d%d",&s[i],&t[i]),val[i]=1,sum[s[i]]++,sum[t[i]]++,v[s[i]].push_back(i),v[t[i]].push_back(i);
	for(int i=1;i<=n;i++){
		for(auto j:v[i]){
			if((s[j]^t[j]^i)>i)continue;
			if(!on[s[j]^t[j]^i])on[s[j]^t[j]^i]=true,val[j]--,sum[i]--;
			hs.insert(sum[s[j]^t[j]^i]); 
		}
		for(auto j:v[i]){
			if((s[j]^t[j]^i)>i)continue;
			if(hs.find(sum[i])==hs.end())break;
			on[s[j]^t[j]^i]=false,val[j]++,sum[i]++;
		}
		hs.clear();
	}
	for(int i=1;i<=n;i++)cnt+=on[i];
	printf("%d
",cnt);
	for(int i=1;i<=n;i++)if(on[i])printf("%d ",i);if(cnt)puts("");
	for(int i=1;i<=m;i++)printf("%d %d %d
",s[i],t[i],val[i]);
	return 0;
}

原文地址:https://www.cnblogs.com/Troverld/p/14621729.html