/*
这是一道维护集合大小的并查集
把所有需要连接在一起的点连在一起
最后输出0号点的根的集合大小即可
*/#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>usingnamespace std;constint N =200010;int n, m;int a, b, len;int p[N], s[N];//找根结点intfind(int x){if(x == p[x])return x;return p[x]=find(p[x]);}//合并voidmerge(int x,int y){int px =find(x);int py =find(y);if(px != py){
p[px]= py;
s[py]+= s[px];}}intmain(){while(~scanf("%d%d",&n,&m)&&(n || m)){for(int i =0; i <= n; i++) p[i]= i, s[i]=1;for(int i =0; i < m; i++){scanf("%d%d",&len,&a);for(int i =1; i < len; i++)scanf("%d",&b),merge(a, b);}//找到0号结点的父结点并输出其集合大小int ans =find(0);printf("%d\n", s[ans]);}}
/*
这道题主要是利用了路径压缩的方法,使得我们在寻找可售时间时的速度更快
具体做法见注释
*/#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>usingnamespace std;constint N =10010;int n, ans;int p[N];struct item {int w, d;//按照商品的价值进行排序,价值相等保质期久的排前面booloperator<(const item &t)const{if(w == t.w)return d > t.d;return w > t.w;}} s[N];intfind(int x){if(x != p[x]) p[x]=find(p[x]);return p[x];}intmain(){while(~scanf("%d",&n)){
ans =0;for(int i =1; i <= n; i++)scanf("%d%d",&s[i].w,&s[i].d);for(int i =0; i < N; i++) p[i]= i;sort(s +1, s + n +1);for(int i =1; i <= n; i++){//day为0说明这个物品已经过保质期无法再选int day =find(s[i].d);if(day){
ans += s[i].w;//父节点直接指向下一个有空的位置(为0就说明没空位了)
p[day]=find(day -1);}}printf("%d\n", ans);}}
/*
这道题在可以看成是食物链那道题的拓展,也是有三个互相克制的关系,然后维护他们的关系找出矛盾之类的东西
但是这道题还有一些特别的地方
这道题我们需要找到一个裁判这个裁判无论怎么出现矛盾都没问题,接下来我们就要寻找这个裁判是谁
那么我们可以枚举每一个人,然后看看除去他以外其他人形成的集合是否能做到没矛盾,可以则说明这个人可以作为裁判
当所有人枚举往以后,我们看看有多少人可以成为裁判如果为0则说明没有,如果为1则说明符合要求,并记录最后一个矛盾点
如果大于一则说明无法确定
*/#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define ll long longusingnamespace std;constint N =2010;struct Node{int u, v, op;}a[N];int n, m, c;int p[N], d[N];voidinit(){for(int i =0; i <= n; i++) p[i]= i, d[i]=0;}intfind(int x){if(p[x]!= x){int y =find(p[x]);
d[x]+= d[p[x]];
p[x]= y;}return p[x];}intmain(){while(~scanf("%d%d",&n,&m)){//先把字符转为数字for(int i =1; i <= m; i++){scanf("%d %c%d",&a[i].u,&c,&a[i].v);if(c =='<') a[i].op =2;elseif(c =='>') a[i].op =1;else a[i].op =0;}int cnt =0, cur =0, q =0;//枚举每一个人作为裁判for(int i =0; i < n; i++){init();int f =1;//枚举每一个关系for(int j =1; j <= m; j++){//涉及到第i个人的关系跳过不处理if(a[j].u == i || a[j].v == i)continue;int u = a[j].u, v = a[j].v, c = a[j].op;int fu =find(u), fv =find(v);if(fu == fv){if(((d[u]- d[v])%3+3)%3!= c){
f =0;//维护最后一个矛盾出现的位置
q =max(q, j);break;}}else{
p[fu]= fv;
d[fu]=((d[v]- d[u]+ c)%3+3)%3;}}if(f){
cnt++;
cur = i;}}if(cnt ==0)puts("Impossible");elseif(cnt >1)puts("Can not determine");elseprintf("Player %d can be determined to be the judge after %d lines\n", cur, q);}}
/*
这道题问的是是否能把给定的结点通过给定的关系构成以可树,这道题我们看看哪些情况无法构成树:
1.维护并查集时出现了环
2.维护完以后出现了森林
*/#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<set>usingnamespace std;constint N =100010;int a, b;int p[N];
set<int> hs;intfind(int x){if(p[x]== x)return x;return p[x]=find(p[x]);}intmain(){while(~scanf("%d%d",&a,&b)){if(a == b && a ==-1)break;if(a ==0&& b ==0){puts("Yes");continue;}
hs.clear();
hs.insert(a), hs.insert(b);//标记当前状态是否可以构成树int f =1;for(int i =1; i < N; i++) p[i]= i;
p[a]= b;while(~scanf("%d%d",&a,&b)&&(a || b)){int pa =find(a), pb =find(b);
hs.insert(a), hs.insert(b);//出现了环if(pa == pb) f =0;else p[pa]= pb;}int h =-1;for(set<int>::iterator i = hs.begin(); i != hs.end()&& f; i++){int cur =*i;//拿第一点的祖宗节点作为标准if(h ==-1) h =find(cur);else{//如果出现其他情况说明出现森林if(h !=find(cur)){
f =0;break;}}}if(f)puts("Yes");elseputs("No");}}
/*
这道题遇上一题相似
但还是要注意一些细节(细节卡了我好久555)
*/#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<set>usingnamespace std;constint N =100010;int a, b, ca;int p[N];
set<int> hs;intfind(int x){if(p[x]== x)return x;return p[x]=find(p[x]);}intmain(){while(~scanf("%d%d",&a,&b)&&(a !=-1|| b !=-1)){if(a ==0&& b ==0){printf("Case %d is a tree.\n",++ca);continue;}int f =1;for(int i =1; i < N; i++) p[i]= i;
hs.clear();
hs.insert(a), hs.insert(b);
p[a]= b;if(a == b) f =0;while(~scanf("%d%d",&a,&b)&&(a || b)){
hs.insert(a), hs.insert(b);int pa =find(a), pb =find(b);//出现自己连自己的情况也不算if(pa == pb || a == b) f =0;else p[pa]= pb;}int cnt =0;for(set<int>::iterator i = hs.begin(); i != hs.end(); i++){int cur =*i;if(find(cur)== cur) cnt++;}if(cnt >1) f =0;if(f)printf("Case %d is a tree.\n",++ca);elseprintf("Case %d is not a tree.\n",++ca);}}