Hacker Cups and Balls Gym - 101234A 二分+线段树

题目:题目链接

题意:有编号从1到n的n个球和n个杯子. 每一个杯子里有一个球, 进行m次排序操作,每次操作给出l,r. 如果l

思路:

  暴力复杂度为m*nlog(n), 不能暴力排序

  二分答案, 对于当前mid, 我们将大于等于mid的数记为1, 否则记0, 则排序就是将某个区间的数改为1或0, 通过线段树区间更新可以方便的做到, 对排序后的结果查询判断二分区间应该取左还是取右, 若中间的数是1, 则说明答案大于等于当前的数, l右移, 否则左移

AC代码:

  1 #include 
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  6 #include 
  7 #include 
  8 #include <string>
  9 #include 
 10 #include <set>
 11 #include 
 12 #include 
 13 #include 
 14 #include 
 15 #include 
 16 
 17 #define FRER() freopen("in.txt", "r", stdin)
 18 #define FREW() freopen("out.txt", "w", stdout)
 19 
 20 #define INF 0x3f3f3f3f
 21 #define eps 1e-8
 22 
 23 using namespace std;
 24 
 25 const int maxn = 1e5 + 5;
 26 
 27 int a[maxn], ql[maxn], qr[maxn], tree[maxn << 2], lazy[maxn << 2];
 28 
 29 void build(int l, int r, int rt, int num) {
 30     lazy[rt] = 0;
 31     if(l == r) {
 32         tree[rt] = (a[l] >= num);
 33         return ;
 34     }
 35     int m = (l + r) >> 1;
 36     build(l, m, rt << 1, num);
 37     build(m + 1, r, rt << 1|1, num);
 38     tree[rt] = tree[rt << 1] + tree[rt << 1|1];
 39 }
 40 
 41 void pushdown(int l, int r, int rt) {
 42     int m = (l + r) >> 1;
 43     lazy[rt << 1] = lazy[rt << 1|1] = lazy[rt];
 44     if(lazy[rt] == 1) {
 45         tree[rt << 1|1] = min(tree[rt], r - m);
 46         tree[rt << 1] = tree[rt] - tree[rt << 1|1];
 47     }
 48     else if(lazy[rt] == 2){
 49         tree[rt << 1] = min(tree[rt], m - l + 1);
 50         tree[rt << 1|1] = tree[rt] - tree[rt << 1];
 51     }
 52     lazy[rt] = 0;
 53 }
 54 
 55 int querySum(int x, int y, int l, int r, int rt) {
 56     if(x <= l && y >= r) return tree[rt];
 57     if(lazy[rt]) pushdown(l, r, rt);
 58     int m = (l + r) >> 1, sum = 0;
 59     if(x <= m) sum += querySum(x, y, l, m, rt << 1);
 60     if(y > m) sum += querySum(x, y, m + 1, r, rt << 1|1);
 61     return sum;
 62 }
 63 
 64 int query(int pos, int l, int r, int rt) {
 65     if(l == r) return tree[rt];
 66     if(lazy[rt]) pushdown(l, r, rt);
 67     int m = (l + r) >> 1;
 68     if(pos <= m) return query(pos, l, m, rt << 1);
 69     else return query(pos, m + 1, r, rt << 1|1);
 70 }
 71 
 72 void update(int x, int y, int l, int r, int rt, int flag, int sum) {
 73     if(x <= l && y >= r) {
 74         tree[rt] = sum;
 75         lazy[rt] = flag;
 76         return ;
 77     }
 78     if(lazy[rt]) pushdown(l, r, rt);
 79     int m = (l + r) >> 1;
 80     if(y <= m) update(x, y, l, m, rt << 1, flag, sum);
 81     else if(x > m) update(x, y, m + 1, r, rt << 1|1, flag, sum);
 82     else {
 83         int lsum, rsum;
 84         if(flag== 1) {
 85             rsum = min(sum, y - m);
 86             lsum = sum - rsum;
 87         }
 88         else if(flag == 2){
 89             lsum = min(sum, m - x + 1);
 90             rsum = sum - lsum;
 91         }
 92         update(x, m, l, m, rt << 1, flag, lsum);
 93         update(m + 1, y, m + 1, r, rt << 1|1, flag, rsum);
 94     }
 95     tree[rt] = tree[rt << 1] + tree[rt << 1|1];
 96 }
 97 
 98 bool judge(int n, int m, int mid) {
 99     build(1, n, 1, mid);
100     for(int i = 0; i < m; ++i) {
101         int sum = querySum(min(ql[i], qr[i]), max(ql[i], qr[i]), 1, n, 1);
102         if(ql[i] <= qr[i]) update(ql[i], qr[i], 1, n, 1, 1, sum);
103         else update(qr[i], ql[i], 1, n, 1, 2, sum);
104     }
105     return query((1 + n) >> 1, 1, n, 1);
106 }
107 
108 int main()
109 {
110     //FRER();
111     ios::sync_with_stdio(0);
112     cin.tie(0);
113 
114     int n, m;
115     cin >> n >> m;
116     for(int i = 1; i <= n; ++i) cin >> a[i];
117     for(int i = 0; i < m; ++i) cin >> ql[i] >> qr[i];
118     int l = 1, r = n, ans;
119     while(l <= r) {
120         int mid = (l + r) >> 1;
121         if(judge(n, m, mid)) 
122             ans = mid, l = mid + 1;
123         else r = mid - 1;
124     }
125     cout << ans << endl;
126     return 0;
127 }

 

你可能感兴趣的:(Hacker Cups and Balls Gym - 101234A 二分+线段树)