题目:CF260D Black and White Tree
本题是一个基于贪心的构造,称之为“打擂法”。
我们把黑白两种颜色的节点分别放到两个数组里面并进行排序。
然后我们每次选两个来自不同集合的所剩权值最小的点进行连边,并把他们所剩的权值都减去连的边权。
接着让所剩权值为0的点下擂台,因为我们用不着它了,它没办法和后面的点进行配对连边。
最后处理剩下还没连的,随便和另一个集合里的点连0权边就行了。
这就是打擂法,适合于贪心类构造题。
upd:本题数据强度不够,我开始写的程序某处有个锅,把a和b打错了,竟然到#26才WA。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #define it register int 4 #define il inline 5 using namespace std; 6 const int N=1000005; 7 struct ky{ 8 int u,val; 9 bool operator<(const ky&p)const{ 10 return val<p.val; 11 } 12 }a[N],b[N]; 13 int n,ca,cb,ci,vali; 14 bool tg[N]; 15 il void fr(int &num){ 16 num=0;char c=getchar();int p=1; 17 while(c<'0'||c>'9') c=='-'?p=-1,c=getchar():c=getchar(); 18 while(c>='0'&&c<='9') num=num*10+c-'0',c=getchar(); 19 num*=p; 20 } 21 int main(){ 22 fr(n); 23 for(it i=1;i<=n;++i) 24 fr(ci),fr(vali),ci?a[++ca]=(ky){i,vali}:b[++cb]=(ky){i,vali}; 25 sort(a+1,a+1+ca),sort(b+1,b+1+cb); 26 it i=1,j=1,minn; 27 while(i<=ca&&j<=cb) 28 minn=(a[i].val<b[j].val?a[i].val:b[j].val),printf("%d %d %d ",a[i].u,b[j].u,minn),a[i].val-=minn,b[j].val-=minn,tg[a[i].u]=tg[b[j].u]=true,!a[i].val?++i:++j; 29 while(i<=ca){ 30 if(!tg[a[i].u]) printf("%d %d 0 ",a[i].u,b[1].u),tg[a[i].u]=1; 31 ++i; 32 } 33 while(j<=cb){ 34 if(!tg[b[j].u]) printf("%d %d 0 ",a[1].u,b[j].u),tg[b[j].u]=1; 35 ++j; 36 } 37 return 0; 38 }