8.20 优先队列+并查集题解
A - Tokens on the Segments ZOJ - 4120
题目大意:给你n个区间,每一次输入的是两个数st,ed。第i次输入代表的区间是(st,i)~(ed,i)所代表的线段。然后让你选择若干个点,使得每一条线段所代表的区间都至少含有一个点被标记。然后问你被标记的线段最多有多少?
具体思路:首先把区间线段放进优先队列中,然后按照左端点从小到大排序,如果相等的话,右端点从小到大排序。每一次判断当前点的左端点是不是大于之前出现过的左端点的最大值。如果大于的话,更新最大值,计数器+1.如果不是,当前点的左端点更新为之前出现过的左端点的最大值+1。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long int ll; 4 const int maxn = 2e5+100; 5 const int N = 110; 6 struct node 7 { 8 ll st,ed; 9 node() {} 10 node(ll xx,ll yy) 11 { 12 st=xx,ed=yy; 13 } 14 bool friend operator < (node t1,node t2) 15 { 16 if(t1.st!=t2.st) 17 return t1.st>t2.st; 18 return t1.ed>t2.ed; 19 } 20 }; 21 int main() 22 { 23 int T; 24 scanf("%d",&T); 25 while(T--) 26 { 27 int n; 28 ll st,ed; 29 scanf("%d",&n); 30 priority_queue<node>w; 31 for(int i=1; i<=n; i++) 32 { 33 scanf("%lld %lld",&st,&ed); 34 w.push(node(st,ed)); 35 } 36 ll maxx=0; 37 int ans=0; 38 while(!w.empty()) 39 { 40 node top=w.top(); 41 w.pop(); 42 if(top.st<=maxx&&top.st+1<=top.ed){ 43 w.push(node(top.st+1,top.ed)); 44 continue; 45 } 46 if(top.st>maxx)ans++,maxx=max(maxx,top.st); 47 } 48 printf("%d\n",ans); 49 } 50 return 0; 51 }
B - Constructing the Array CodeForces - 1353D
题意大意:一个长度为 nnn 的数组,初始值全部为 0,每次选择其中最长的一段全 0 连续子数组,如果多个并列最长,取最左边的那个,并标记其左右区间 LR如果这个子数组包含的元素个数为奇数(R−L+1为奇数),则将这一段区间最中间那个位置标记上数字,如果这个子数组包含的元素个数为偶数,则将这一段区间内中间靠左的那个位置标记上数字数字依次标记 1−n,最后输出这个数组。
具体思路:每次操作后,把左右两个区间都放到优先队列,然后让长度最长且靠近左边的优先出队就好了。
1 #include<algorithm> 2 #include<cstdio> 3 #include<iostream> 4 #include<queue> 5 #include<vector> 6 #include<map> 7 #include<stack> 8 #include<string> 9 #include<cmath> 10 #include<sstream> 11 #include<cstring> 12 #include<set> 13 using namespace std; 14 typedef long long int ll; 15 typedef unsigned long long int ull; 16 const int N = 2e5+10; 17 const int M = 1e6 + 10; 18 int arr[N]; 19 struct node { 20 int l, r, cha; 21 bool operator <(const node& a)const { 22 if (cha == a.cha)return l > a.l; 23 return cha < a.cha; 24 } 25 }; 26 int main() { 27 Case(T) { 28 scanf("%d",&n); 29 int tot = 1; 30 priority_queue<node>q; 31 q.push({1,n,n}); 32 while (!q.empty()) { 33 node u = q.top(); 34 q.pop(); 35 int l = u.l, r = u.r; 36 int mid = l+r >> 1; 37 arr[mid] = tot++; 38 if (mid - 1 >= l)q.push({ l,mid - 1,mid - l }); 39 if (mid + 1 <= r)q.push({ mid + 1,r,r - mid }); 40 } 41 rep(i, 1, n)cout << arr[i] << " "; 42 puts(""); 43 } 44 45 }
C - How Many Tables HDU - 1213
具体思路:利用并集查的思想,首先假设n个人互不认识,那么共需n张桌子,然后根据输入建立联系后,每一有一个认识就减少一张桌子。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<queue> 5 #include<map> 6 #include<vector> 7 #include<set> 8 #include<string> 9 #include<cmath> 10 #include<cstring> 11 #define INF 0x3f3f3f3f3f3f3f3f 12 using namespace std; 13 const int maxn = 2000; 14 int fa[maxn]; 15 void init() { 16 for (int i = 1;i <= maxn;i++) { 17 fa[i] = i; 18 } 19 } 20 int find(int x) { 21 return x == fa[x] ? x : fa[x] = find(fa[x]); 22 } 23 void father(int x, int y) { 24 int fx = find(x); 25 int fy = find(y); 26 fa[fx] = fy; 27 } 28 int main() 29 { 30 ios::sync_with_stdio(false); 31 cin.tie(0); 32 cout.tie(0); 33 int t; 34 scanf("%d", &t); 35 while (t--) { 36 init(); 37 int n, m; 38 scanf("%d %d", &n, &m); 39 while (m--) { 40 int a, b; 41 scanf("%d %d", &a, &b); 42 father(a, b); 43 } 44 vector<int>v; 45 for (int i = 1;i <= n;i++) { 46 int res = find(i); 47 if (find(v.begin(), v.end(), res) == v.end()) { v.push_back(res); } 48 } 49 printf("%d\n", v.size()); 50 } 51 52 }
D - The Suspects POJ - 1611
具体思路见代码解释。
1 #include<algorithm> 2 #include<cstdio> 3 #include<iostream> 4 #include<queue> 5 #include<vector> 6 #include<map> 7 #include<stack> 8 #include<string> 9 #include<cmath> 10 #include<sstream> 11 #include<cstring> 12 #include<set> 13 using namespace std; 14 typedef long long int ll; 15 typedef unsigned long long int ull; 16 const int N = 5e5+10; 17 int father[N]; 18 void init() {//初始化 19 for (int i = 0;i < N;i++) { 20 father[i] = i; 21 } 22 } 23 int find(int x) {//查找 24 if (x == father[x]) { 25 return x; 26 } 27 else { 28 father[x] = find(father[x]);//路径压缩 29 } 30 } 31 void merge(int x, int y) {//联结集合 32 int fx = find(x); 33 int fy = find(y); 34 father[fx] = fy; 35 } 36 int main() { 37 int n, m; 38 while (~scanf("%d%d", &n, &m),n+m) { 39 init(); 40 while (m--) { 41 int num, p1;//num是团体人数,p1是团体的第一个人 42 cin >> num >> p1; 43 for (int i = 1;i < num;i++) { 44 int person; 45 cin >> person;//读入团体中的人 46 merge(person, p1); 47 } 48 } 49 int ac = find(0);//小A所属的集合 50 int ans = 0; 51 for (int i = 0;i <= n - 1;i++) { 52 if (find(i) == ac)ans++;//如果和小A集合相同说明需要隔离 53 } 54 cout << ans << endl; 55 } 56 }