题目:题目链接
题意:有编号从1到n的n个球和n个杯子. 每一个杯子里有一个球, 进行m次排序操作,每次操作给出l,r. 如果l<r,将[l,r]范围内的球按升序排序, 否则降序排, 问中间位置的数是多少.
思路:
暴力复杂度为m*nlog(n), 不能暴力排序
二分答案, 对于当前mid, 我们将大于等于mid的数记为1, 否则记0, 则排序就是将某个区间的数改为1或0, 通过线段树区间更新可以方便的做到, 对排序后的结果查询判断二分区间应该取左还是取右, 若中间的数是1, 则说明答案大于等于当前的数, l右移, 否则左移
AC代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cmath> 6 #include <algorithm> 7 #include <vector> 8 #include <string> 9 #include <map> 10 #include <set> 11 #include <unordered_map> 12 #include <unordered_set> 13 #include <queue> 14 #include <stack> 15 #include <list> 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 }