题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2860
题目大意:新兵入伍。三种操作:①入伍②合并队伍③查找一个队伍里面战斗力最弱的。注意队伍编号从0开始。
解题思路:
单看入伍的话,很容易想到以士兵为单位建立并查集。
然而到了合并队伍、查询的时候,就没办法了。
更直接的,以队伍为单位建立并查集,这样只要$f[x]!=x$,说明队伍已被合并。
当然,最重要的,就是查询之前,没必要路径压缩,因为只需要简单判断$f[x]!=x$,而不是查f[x]的具体值。
同时用cap数组维护每个队伍的最弱战斗力。
维护
①入伍时候,先Judge $f[x]!=x$。
若存在,此时只需Min更新一下队伍的战斗力就可以。
②合并队伍,先Judge $f[x]==x$&&$f[y]==y$&&$x!=y$,直接令$f[y]=x$,并且更新,不需要路径压缩。
反之,拒绝合并。
查询
①成功输出的条件是:$f[x]==x$&&$cap[x]!=inf$
②空队伍的条件是:$f[x]==x$&&$cap[x]==inf$ (注意,转移之后,就算是空队伍,也在③中处理)
③转移队伍的条件是:$f[x]!=x$ ,查询时候,再find路径压缩即可。
代码
#include "cstdio" #include "cstring" #include "algorithm" using namespace std; #define maxn 100005 #define inf 0x3f3f3f3f int f[maxn],cap[maxn]; int find(int x) {return x!=f[x]?f[x]=find(f[x]):x;} int main() { //freopen("in.txt","r",stdin); int n,k,m,R,C; while(scanf("%d%d%d",&n,&k,&m)!=EOF) { for(int i=0;i<=n;i++) f[i]=i; memset(cap,inf,sizeof(cap)); for(int i=1;i<=k;i++) { scanf("%d%d",&R,&C); cap[C]=min(cap[C],R); } char cmd[5]; for(int i=1;i<=m;i++) { scanf("%s",&cmd); if(cmd[0]==‘A‘) { scanf("%d%d",&R,&C); if(f[C]!=C) {printf("Reject\n");continue;} cap[C]=min(cap[C],R); printf("Accept\n"); } if(cmd[0]==‘M‘) { scanf("%d%d",&R,&C); if(f[R]==R&&f[C]==C&&R!=C) {f[C]=R;cap[R]=min(cap[R],cap[C]);printf("Accept\n");} else printf("Reject\n"); } if(cmd[0]==‘G‘) { scanf("%d",&R); if(f[R]==R&&cap[R]!=inf) printf("Lowest rate: %d.\n",cap[R]); else if(f[R]==R&&cap[R]==inf) printf("Company %d is empty.\n",R); else if(f[R]!=R) printf("Company %d is a part of company %d.\n",R,find(R)); } } printf("\n"); } }
时间: 2024-11-17 07:31:30