首页 > 代码库 > CodeForces - 356A Knight Tournament

CodeForces - 356A Knight Tournament

http://codeforces.com/problemset/problem/356/A

首先理解题意 

每次给出l 和r  在l - r之间还有资格的选手中得出一个胜者

暴力思路:

首先维护还有资格的选手的集合 

用一个数组 表示 这个选手被谁击败

每次遍历 l - r 然后把不是胜者 且 还在集合中的选手踢出 并更新这个选手的数组值

最终 输出这个数组即可

这样会TLE 

1、 如果用数组维护这个集合的话 每次遍历都是这样就是O(n^2) -->> 所以用set维护这个集合

2、使用set后 如果每次依然从l - r去遍历找在集合中的元素 去find的话 那么就会在 (l, r)的区间两端有浪费的运算 如果每次l, r 都是1 和 n的话 那就浪费得非常得多

   所以使用set :: lower_bound() 直接得到第一个大于l 并在集合中的元素 O(logn)

这样优化后 即可

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <set>
 4 using namespace std;
 5 
 6 
 7 int Par[300007];
 8 int tmp[300007];
 9 set<int> s;
10 
11 int find(int x)
12 {
13     if (Par[x] == x) return x;
14     else return find(Par[x]);
15 }
16 
17 int main()
18 {
19     int n, m;
20     freopen("in.txt", "r", stdin);
21     scanf("%d%d", &n, &m);
22     for (int i = 0; i <= n; i++)
23     {
24         Par[i] = i;
25         s.insert(i);//加入set中
26     }
27     for(int i = 0; i < m; i++)
28     {
29         int l, r, x;
30         scanf("%d%d%d", &l, &r, &x);
31         set<int> :: iterator pit = s.lower_bound(l);//返回第一个>= l的位置
32         int num = 0;
33         while (pit != s.end() && (*pit) <= r )
34         {
35             if ((*pit) != x)
36             {
37                 Par[*pit] = x;
38                 //s.erase(*pit); 不能在这里直接删除 删除后set结构发生改变 pit就失效了
39                 tmp[num++] = *pit;
40             }
41             pit++;
42         }
43         for (int j = 0; j < num; j++) s.erase(tmp[j]);
44     }
45     for (int i = 1; i <= n; i++)
46     {
47         if (Par[i] == i) printf("0 ");
48         else printf("%d ", Par[i]);
49     }
50     putchar(\n);
51 }

 

CodeForces - 356A Knight Tournament