老头马桶枪!
Time Limit: 1000 MS Memory Limit: 64 MB
众所周知,集训队的题目是非常困难的。因此,队员们在挂机AK之后,常常会玩一些游戏。
这次,率先AK的周大爷想出了一个叫老头马桶枪的游戏。
在一个小岛上,有三个物种,一共N个生物生活在一起,他们分别是老头、马桶和枪。他们之间的关系是相互克制的,就像包剪锤一样。老头克制马桶,马桶克制枪,枪又克制老头。
现在,集训队的三名成员,小周,小钱和小胡按次序(周、钱、胡)轮流给出信息,信息有两种形式:
第一种记录方式是1 X Y
是同类。
第二种记录方式是2 X Y
,表示 X对 Y有攻击性行为( X克制 Y)。
当其中一人给出的信息和之前的人给出的信息矛盾时,他便输了,要请吃晚饭。那么,聪明的你能帮助他们看出谁会输呢?(最多只会有一个人输,当多条信息矛盾时,最先给出矛盾信息的人输)
Input
第一行包含两个整数N
Output
输出一行,表示最先给出矛盾信息的人是谁。若是小周,输出1
;若是小钱,输出2
;若是小胡,输出3
;若没有人给出矛盾信息,输出-1
。
Sample input and output
Sample Input | Sample Output |
---|---|
100 7 1 100 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5 |
1 |
Source
UESTC Online Judge
Copyright (C) 2012 - 2018 Ruins He(@ruinshe), Jianjin Fan(@pfctgeorge) and Yun Li(@mzry1992). Project home
Any Problem, Please Report On Issues Page.
这一题仿照poj1182的食物链https://blog.csdn.net/keepcoral/article/details/79946060
食物链循环,a->b,b->c,c->a,这里学到一种新的方法,上面写的实在有点难懂,特别是推到关系那里,真的很难想,这里从别人博客上学到了新方法。
首先,有n个动物,那么我们开辟3n个集合,x,x+n,x+2n,分别表示与x同类,被x吃的,吃x的集合,所以两个动物x和y下面有两种情况:
1 x和y是同类,那么和y同类的即等价于和x同类,吃y的等价于吃x的,被y吃的等价于被x吃的,所以这三个集合要同时合并,
Union(x,y);
Union(x+n,y+n);
Union(x+2*n,y+2*n)
判断真假条件:x被y吃||x吃y,那么直接表示就是x在y+n的集合||x在y+2n的集合,这里y+n代表被y吃的集合,y+2n代表吃y的集合,所以判断条件为judge(x,y+n)&&judge(x,y+2n),
2 x吃y,那么被y吃的等价于吃x的,和y同类的等价于被x吃的,吃y的等价于x的同类,所以集合为
Union(x,y+n);
Union(x+n,y+2*n);
Union(x+2*n,y);
判断真假条件:x和y同类||y吃x,所以条件为 judge(x,y)&&judge(x,y+n)(我的代码可能会有点出入,因为n和2*n我写的恰好相反的)
这里的合并是最关键的操作,下面的几道题也是一样,也就是当不知道情况的时候才可以去合并,这是题目的要求
#include<iostream> #include<string> #include<vector> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #include<set> #include<stack> #include<queue> #include<string> #include<map> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; int father[300009]; int Find(int x) { if(x!=father[x]) father[x]=Find(father[x]); return father[x]; } int Union(int x,int y) { int i=Find(x); int j=Find(y); if(i!=j) father[i]=j; } int judge(int x,int y) { int i=Find(x); int j=Find(y); if(i!=j)//不同类 { return 1; } else return 0; } int main() { int n,m,i,j,k; scanf("%d%d",&n,&m); for(i=1;i<=3*n;i++) father[i]=i; for(i=1; i<=m; i++) { int op,x,y; scanf("%d%d%d",&op,&x,&y); if(op==1)//x和y是同类,所以判断不同类 { if(judge(x,y+n)&&judge(x,y+2*n)) { Union(x,y); Union(x+n,y+n); Union(x+2*n,y+2*n); } else { if(i%3!=0)printf("%d\n",i%3); else printf("3\n"); break; } } else//x吃y,要判断同类或者y吃x { if(judge(x,y)&&judge(x,y+2*n)) { Union(x,y+n); Union(x+n,y+2*n); Union(x+2*n,y); } else { if(i%3!=0)printf("%d\n",i%3); else printf("3\n"); break; } } } if(i==m+1) printf("-1\n"); return 0; }
I - 不如把并查集加上个计数功能吧
Time Limit: 1000 MS Memory Limit: 64 MB
在另一个宇宙,一个月有 N
天一样。
但民众并不满足于此,他们想知道有多少天的天气和第 X
天一样。现在,作为一个聪明的程序员,你能帮他们解决这个问题吗?
Input
第一行包含两个整数N
Output
对于每一个询问,输出一行,包含一个整数,表示和z
天气一样的天数。
Sample input and output
Sample Input | Sample Output |
---|---|
10 5 1 2 2 3 3 4 1 5 6 7 2 1 6 |
5 2 |
UESTC Online Judge
Copyright (C) 2012 - 2018 Ruins He(@ruinshe), Jianjin Fan(@pfctgeorge) and Yun Li(@mzry1992). Project home
Any Problem, Please Report On Issues Page.
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<iostream> using namespace std; typedef unsigned long long ll; #define N 100009 #define M 400090 #define C 18446744073709551611 int father[N]; int sum[N]; int n,m; int Find(int x) { if(father[x]!=x) father[x]=Find(father[x]); return father[x]; } void Union(int x,int y) { int i=Find(x); int j=Find(y); if(i!=j) { father[i]=j; sum[j]+=sum[i]; } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { father[i]=i; sum[i]=1; } while(m--) { int x,y; scanf("%d%d",&x,&y); Union(x,y); } for(int i=1;i<=n;i++) Find(i); scanf("%d",&m); while(m--) { int x; scanf("%d",&x); printf("%d\n",sum[father[x]]); } }
K - 爱吃瓜的伊卡洛斯(1)
Time Limit: 1000 MS Memory Limit: 64 MB
伊卡洛斯很爱吃西瓜。一次,他来到一个西瓜摊旁,发现水果摊有N个西瓜,但只有红色和黄色两种颜色。
伊卡洛斯很想知道知道一些信息,便于老板交谈了起来。
当老板的话的第一个字符为”A”时,老板会告诉伊卡洛斯一些信息,格式如下:
A x y 1 这句话表示第x个西瓜和第y个西瓜是同一种颜色的。
A x y 2 这句话表示第x个西瓜和第y个西瓜是不同种颜色的。
当然,为了考验伊卡洛斯有没有认真听, 老板也会时不时问伊卡洛斯一些问题,格式如下:
Q x y 这句话表示询问第x个西瓜和第y个西瓜是不是同一种颜色,如果确定为同一种颜色,伊卡洛斯需要回答1
;确定为不同种颜色,伊卡洛斯需要回答2
;无法确定时伊卡洛斯回答3
。
注意,伊卡洛斯是根据已获得的信息来回答的。也就是只有这个问题之前的信息才为已知信息。
老板说,只有回答对他全部的问题,伊卡洛斯才能吃到瓜,他聪明的想到了让你来帮助他。
Input
第一行包含两个整数N和M,N是西瓜总数,M是以A或Q开头的老板的话总和。
以下M行,每行包含一条老板的话。形式有A x y 1或A x y 2或Q x y。1≤N≤100000 1≤M≤200000 1≤X,Y≤N数据保证没有矛盾
Output
对于每一条$Q$指令,输出1
/2
/3
代表两个西瓜颜色的关系。
Sample input and output
Sample Input | Sample Output |
---|---|
6 9 A 1 2 1 A 1 3 1 A 1 4 2 Q 2 4 Q 1 6 A 3 6 1 A 4 5 2 Q 1 5 Q 1 6 |
2 3 1 1 |
Hint
西瓜的颜色有且仅有两种!
对立面的并查集,x表示同色的,x+n表示和x不同颜色的,所以如果说了不同颜色,那么Union(x,y),Union(x+n,y+n) 如果不同颜色,那么Union(x,y+n),Union(x+n,y),这里简单来说就是x和y不同颜色,那么x属于和y不同颜色的集合(y+n)这里。查询的时候,如果Find(x)==Find(y),同色;如果Find(x)=Find(y+n)||Find(y)=Find(x+n),不同色;其它不清楚
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<iostream> using namespace std; typedef unsigned long long ll; #define N 100009 #define M 400090 #define C 18446744073709551611 int father[5*N]; int sum[N]; int n,m; int Find(int x) { if(father[x]!=x) father[x]=Find(father[x]); return father[x]; } void Union(int x,int y) { int i=Find(x); int j=Find(y); if(i!=j) { father[i]=j; } } int main() { char s[10]; scanf("%d%d",&n,&m); for(int i=1; i<=2*n; i++) { father[i]=i; } while(m--) { int x,y,flag; scanf("%s%d%d",&s,&x,&y); if(s[0]=='A') { scanf("%d",&flag); if(flag==1) { Union(x,y); Union(x+n,y+n); } else if(flag==2) { Union(x,y+n); Union(y,x+n); } } else { if(Find(x)==Find(y)) printf("1\n"); else if(Find(x)==Find(y+n)||Find(y)==Find(x+n)) printf("2\n"); else printf("3\n"); } } }
L - 爱吃瓜的伊卡洛斯(2)
Time Limit: 1000 MS Memory Limit: 64 MB
伊卡洛斯很爱吃西瓜。一次,他来到一个西瓜摊旁,发现水果摊有$N$个西瓜,西瓜有红色、黄色、绿色、蓝色……等等数不清的颜色。伊卡洛斯很想知道知道一些信息,便于老板交谈了起来。当老板的话的第一个字符为”A
”时,老板会告诉伊卡洛斯一些信息,格式如下:$A\ x\ y\ 1$ 这句话表示第$x$个西瓜和第$y$个西瓜是同一种颜色的。$A\ x\ y\ 2$ 这句话表示第$x$个西瓜和第$y$个西瓜是不同种颜色的。
当然,为了考验伊卡洛斯有没有认真听, 老板也会时不时问伊卡洛斯一些问题,格式如下:$Q\ x\ y$ 这句话表示询问第$x$个西瓜和第$y$个西瓜是不是同一种颜色,如果确定为同一种颜色,伊卡洛斯需要回答1
;确定为不同种颜色,伊卡洛斯需要回答2
;无法确定时伊卡洛斯回答3
。注意,伊卡洛斯是根据已获得的信息来回答的。也就是只有这个问题之前的信息才为已知信息。
老板说,只有回答对他全部的问题,伊卡洛斯才能吃到瓜,他聪明的想到了让你来帮助他。
Input
第一行包含两个整数N
以下 M行,每行包含一条老板的话。形式有 A x y 1或 A x y 2或 Q x y。 1≤N≤100000 1≤M≤200000 1≤X,Y≤N
数据保证没有矛盾
Output
对于每一条Q
指令,输出1
/2
/3
代表两个西瓜颜色的关系。
Sample input and output
Sample Input | Sample Output |
---|---|
6 9 A 1 2 1 A 1 3 1 A 1 4 2 Q 2 4 Q 1 6 A 3 6 1 A 4 5 2 Q 1 5 Q 1 6 |
2 3 3 1 |
Hint
西瓜的颜色可以有无数多种!
#include <iostream> #include <cstdio> #include <string> #include <set> using namespace std; int father[100009]; set<int>s[100009];//代表s[x]代表和x不同的元素的集合 int Find(int x) { if(x!=father[x]) father[x]=Find(father[x]); return father[x]; } void Union(int i,int j) { int x=Find(i); int y=Find(j); if(x!=y) { if(s[x].size()>s[y].size()) swap(s[x],s[y]);//小的合并到大的 father[x]=y; for(set<int>::iterator it=s[x].begin(); it!=s[x].end(); it++) { s[y].insert(Find(*it));//找到根节点 } } } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) { father[i]=i; } while(m--) { char c[10]; scanf("%s",c); if(c[0]=='A') { int x,y,z; scanf("%d%d%d",&x,&y,&z); if(z==1) { Union(x,y); } else { x=Find(x); y=Find(y); s[x].insert(y); s[y].insert(x); } } else { int x,y; scanf("%d%d",&x,&y); x=Find(x); y=Find(y); if(x==y) printf("1\n"); else if(s[x].count(y)==1||s[y].count(x)==1) printf("2\n");//在对应的set里面的找到了相应元素 //证明这两个元素是不同的 else printf("3\n"); } } }
E - 小埋的steam愿望单
Time Limit: 2000 MS Memory Limit: 64 MB
小埋有一个steam愿望单,上面记载着她想买的游戏!现在小埋有以下 $n$ 个操作:
$1\ x\ y$ 添加一个价格为 $y$ 名字为 $x$ 的游戏加入愿望单
$2\ x$ 删除名字为 $x$ 的游戏
$3\ x\ y$ 名字为 $x$ 的游戏价格调整为 $y$
$4\ x$ $x$ 为 $1$ 输出最便宜的游戏的名字(如果有多个同价格游戏输出字典序最小的),$x$ 为 $2$ 输出最贵的游戏(如果有多个同价格游戏输出字典序最大的)
不合法的情况请忽略该操作
不合法的情况请忽略该操作
不合法的情况请忽略该操作
Input
第一行一个$n(1\le n \le 1e5)$接下来 $n$ 行 每行一个 $p$ 表示操作类型 接下来根据操作类型跟一个或两个数字( $x$ 只包括大小写字母和下划线并不超过25个字符,$1\le y\le 1e9$)
Output
对于每个查询,输出一行对应游戏的名字
Sample input and output
Sample Input | Sample Output |
---|---|
8 1 slay_the_spire 60 1 dark_soul_III 118 1 The_Binding_of_Isaac 58 1 Age_of_Empires_II 88 4 1 3 dark_soul_III 57 4 1 4 2 |
The_Binding_of_Isaac dark_soul_III Age_of_Empires_II |
7 4 1 1 I 100 1 II 150 1 I 200 4 1 2 III 3 IV 600 |
#include<iostream> #include<string> #include<vector> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #include<set> #include<stack> #include<queue> #include<string> #include<map> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; struct node { int v; string name; friend bool operator < (node a,node b) { if(a.v==b.v) return a.name<b.name; else return a.v<b.v; } } c[100009]; set<node>s; map<string,int>m; int main() { int n,ans=1; scanf("%d",&n); while(n--) { int flag,v; string a; node temp; scanf("%d",&flag); if(flag==1) { cin>>a>>v; if(m.count(a)==0) { temp.name=a; temp.v=v; s.insert(temp); m[a]=ans; c[ans++]=temp; } } else if(flag==2) { cin>>a; if(m.count(a)==1) { s.erase(c[m[a]]); m.erase(a); } } else if(flag==3) { cin>>a>>v; if(m.count(a)==1) { s.erase(c[m[a]]); c[m[a]].v=v; s.insert(c[m[a]]); } } else { set<node>::iterator it; cin>>v; if(s.size()) { if(v==1) { it=s.begin(); cout<<(*it).name<<endl; } else { it=s.end(); it--; cout<<(*it).name<<endl; } } } } }
三澄美琴是一个热爱学习的法医,今天晚上她准备下载很多很多法医论文资料。下面有三个操作
1 ti ai bi
i 在 ti时刻加入了编号为 ai耗时为 bi的论文进入下载队列
2 ti
在 ti时刻取消队列首位的任务(如果下载队列为空就忽略该操作)
3 ti
查询在 ti时刻队列首位的任务编号,无下载任务输出 -1
Input
第一行一个n
接下来 n行,每行 j(1≤j≤3),ti(1≤ti≤1e9,升序输出),当 j=1 时, ti 后会跟 ai(1≤ai≤n), bi(1≤bi≤1e4)
Output
对于每个3号操作输出一行,输出目前队列首位的论文编号
Sample input and output
Sample Input | Sample Output |
---|---|
6 1 1 1 5 3 2 1 3 2 3 2 4 3 5 3 6 |
1 2 -1 |
Hint
样例解释
操作一:在第1秒加入了编号为1的论文,耗时5秒,将于第6秒完成
操作二:在第1秒查询,队列首位为编号1
操作三:在第3秒加入编号为2的论文下载,耗时3秒,将于第6秒完成,队列里有两个下载任务,队列首位为编号1
操作四:在第4秒移除了编号为1的论文,目前队列里有一个下载任务,队列首位为编号2
操作五:在第5秒查询,队列首位为编号2
操作六:在第6秒查询,此时2号任务刚好完成,队列为空,输出-1
#include<iostream> #include<string> #include<vector> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #include<set> #include<stack> #include<queue> #include<string> #include<map> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; struct node { int id,t; }; queue<node>q; int main() { int m; scanf("%d",&m); while(m--) { int op,begin,t; node temp; scanf("%d",&op); if(op==1) { cin>>begin>>temp.id>>t; temp.t=begin+t; q.push(temp); } else if(op==2) { cin>>t; while(!q.empty()) { if(t>=q.front().t) q.pop(); else { q.pop(); break; } } } else { cin>>t; while(!q.empty()) { if(t>=q.front().t) q.pop(); else { printf("%d\n",q.front().id); break; } } if(q.empty()) printf("-1\n"); } } }