题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=4552
题意:给出一个$1$到$N$的全排列,对其进行$M$次排序,每次排序将区间$[l,r]$从小到大或从大到小排序,求排序完后位置$q$上的数字。$N,M \leq 10^5$,时限$6s$
名字挂羊头卖狗肉……
暴力排序$O(NMlogN)$神级常数才能过,故考虑在排序上降低复杂度
考虑二分答案,将小于等于当前答案的设为$0$,大于当前答案的设为$1$,这样修改就变成$0,1$排序,可以使用线段树区间覆盖实现
时间复杂度$O(Mlog^2N)$
1 #include<bits/stdc++.h>
2 #define MAXN 100005
3 using namespace std;
4 inline int read(){
5 int a = 0;
6 char c = getchar();
7 while(!isdigit(c))
8 c = getchar();
9 while(isdigit(c)){
10 a = (a << 3) + (a << 1) + (c ^ '0');
11 c = getchar();
12 }
13 return a;
14 }
15
16 struct node{
17 int l , r , mark , num1;
18 }Tree[MAXN << 4];
19 int num[MAXN] , N , sortNum[MAXN][3] , M , askNum , mid;
20
21 inline void pushup(int dir){
22 Tree[dir].num1 = Tree[dir << 1].num1 + Tree[dir << 1 | 1].num1;
23 }
24
25 inline void pushdown(int dir){
26 if(Tree[dir].mark == 0)
27 Tree[dir << 1].mark = Tree[dir << 1 | 1].mark = Tree[dir << 1].num1 = Tree[dir << 1 | 1].num1 = 0;
28 else
29 if(Tree[dir].mark == 1){
30 Tree[dir << 1].mark = Tree[dir << 1 | 1].mark = 1;
31 Tree[dir << 1].num1 = Tree[dir << 1].r - Tree[dir << 1].l + 1;
32 Tree[dir << 1 | 1].num1 = Tree[dir << 1 | 1].r - Tree[dir << 1 | 1].l + 1;
33 }
34 Tree[dir].mark = -1;
35 }
36
37 void init(int l , int r , int dir){
38 Tree[dir].l = l;
39 Tree[dir].r = r;
40 Tree[dir].mark = -1;
41 if(l == r)
42 Tree[dir].num1 = num[l] > mid;
43 else{
44 init(l , l + r >> 1 , dir << 1);
45 init((l + r >> 1) + 1 , r , dir << 1 | 1);
46 pushup(dir);
47 }
48 }
49
50 void change(int l , int r , int dir , int mark){
51 if(Tree[dir].l >= l && Tree[dir].r <= r){
52 Tree[dir].mark = mark;
53 Tree[dir].num1 = mark * (Tree[dir].r - Tree[dir].l + 1);
54 return;
55 }
56 pushdown(dir);
57 if(l <= Tree[dir].l + Tree[dir].r >> 1)
58 change(l , r , dir << 1 , mark);
59 if(r > Tree[dir].l + Tree[dir].r >> 1)
60 change(l , r , dir << 1 | 1 , mark);
61 pushup(dir);
62 }
63
64 int ask(int l , int r , int dir){
65 if(Tree[dir].l >= l && Tree[dir].r <= r)
66 return Tree[dir].num1;
67 int sum = 0;
68 pushdown(dir);
69 if(l <= Tree[dir].l + Tree[dir].r >> 1)
70 sum += ask(l , r , dir << 1);
71 if(r > Tree[dir].l + Tree[dir].r >> 1)
72 sum += ask(l , r , dir << 1 | 1);
73 return sum;
74 }
75
76 inline bool check(){
77 init(1 , N , 1);
78 for(register int i = 1 ; i <= M ; i++){
79 int t = ask(sortNum[i][1] , sortNum[i][2] , 1);
80 if(sortNum[i][0]){
81 change(sortNum[i][1] , sortNum[i][1] + t - 1 , 1 , 1);
82 if(sortNum[i][1] + t <= sortNum[i][2])
83 change(sortNum[i][1] + t , sortNum[i][2] , 1 , 0);
84 }
85 else{
86 change(sortNum[i][2] - t + 1, sortNum[i][2] , 1 , 1);
87 if(sortNum[i][2] - t >= sortNum[i][1])
88 change(sortNum[i][1] , sortNum[i][2] - t , 1 , 0);
89 }
90 }
91 return !ask(askNum , askNum , 1);
92 }
93 int main(){
94 N = read();
95 M = read();
96 for(register int i = 1 ; i <= N ; i++)
97 num[i] = read();
98 for(register int i = 1 ; i <= M ; i++){
99 sortNum[i][0] = read();
100 sortNum[i][1] = read();
101 sortNum[i][2] = read();
102 }
103 askNum = read();
104 int l = 1 , r = N;
105 while(l < r){
106 mid = l + r >> 1;
107 if(check())
108 r = mid;
109 else
110 l = mid + 1;
111 }
112 cout << l;
113 return 0;
114 }