CF260D Black and White Tree

发布时间 2023-10-19 20:34:51作者: 空気力学の詩

刚开始想复杂了,后面再细想了下发现是个傻逼题

考虑一下构造策略,每次从两种颜色集合中分别取出一个数\(u,v\),考虑连边\(u\leftrightarrow v\),边权为\(\min(s_u,s_v)\)

并在每次操作后将\(s_u,s_v\)中较小的那个直接删掉,并把较大的那个值减去\(\min(s_u,s_v)\),重复\(n-1\)次即可得到一组合法解

这样做的正确性显然,因为可以用边权为\(0\)的边,因此总能保证树是连通的,且由于只构造了\(n-1\)条边,因此不会成环

#include<cstdio>
#include<iostream>
#include<utility>
#include<vector>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<set>
#include<array>
#include<random>
#include<bitset>
#include<ctime>
#include<limits.h>
#include<assert.h>
#include<unordered_set>
#include<unordered_map>
#define RI register int
#define CI const int&
#define mp make_pair
#define fi first
#define se second
#define Tp template <typename T>
using namespace std;
typedef long long LL;
typedef long double LDB;
typedef unsigned long long u64;
typedef __int128 i128;
typedef pair <int,int> pi;
typedef vector <int> VI;
typedef array <int,3> tri;
const int N=100005;
int n,c,s[N]; vector <int> id[2];
int main()
{
	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
	RI i,j,k; for (scanf("%d",&n),i=1;i<=n;++i)
	scanf("%d%d",&c,&s[i]),id[c].push_back(i);
	for (i=j=0,k=1;k<n;++k)
	{
		int x=id[0][i],y=id[1][j],w=min(s[x],s[y]);
		printf("%d %d %d\n",x,y,w); s[x]-=w; s[y]-=w;
		if (i+1<id[0].size()&&s[x]==0) ++i; else ++j;
	}
	return 0;
}