题干:
DZY has a sequence a[1..n]a[1..n]. It is a permutation of integers 1∼n1∼n.
Now he wants to perform two types of operations:
0lr0lr: Sort a[l..r]a[l..r] in increasing order.
1lr1lr: Sort a[l..r]a[l..r] in decreasing order.
After doing all the operations, he will tell you a position kk, and ask you the value of a[k]a[k].
Input
First line contains tt, denoting the number of testcases.
tt testcases follow. For each testcase:
First line contains n,mn,m. mm is the number of operations.
Second line contains nn space-separated integers a[1],a[2],⋯,a[n]a[1],a[2],⋯,a[n], the initial sequence. We ensure that it is a permutation of 1∼n1∼n.
Then mm lines follow. In each line there are three integers opt,l,ropt,l,r to indicate an operation.
Last line contains kk.
(1≤t≤50,1≤n,m≤100000,1≤k≤n,1≤l≤r≤n,opt∈{0,1}1≤t≤50,1≤n,m≤100000,1≤k≤n,1≤l≤r≤n,opt∈{0,1}. Sum of nn in all testcases does not exceed 150000150000. Sum of mm in all testcases does not exceed 150000150000)
Output
For each testcase, output one line - the value of a[k]a[k] after performing all mmoperations.
Sample Input
1 6 3 1 6 2 5 3 4 0 1 4 1 3 6 0 2 4 3
Sample Output
5
Hint
1 6 2 5 3 4 -> [1 2 5 6] 3 4 -> 1 2 [6 5 4 3] -> 1 [2 5 6] 4 3. At last $a[3]=5$.
题目大意:
解题报告:
两个log的做法展现了二分答案的强大功能。首先二分枚举第 k 位的值x,然后将大于等于x的数都变为 1 ,小于x的数变为 0 ,这样这数字序列就变成了01序列,只有这两种性质。我们用线段树不难实现对 01 序列按要求进行排序,然后如果第 k 位为 1 说明x可以是ans但是太小了,要调整下界。就这样不断二分下来,得到的边界值就是第 k 位真实的值。这个做法是离线的,有两个log ,但代码好实现。
这题巧妙之处:第一在于只有一次查询,第二在于是n的全排列。(但是貌似不是全排列也可用类似的方法做。)
nlogn的神仙方法:https://www.cnblogs.com/Paulliant/p/10185235.html(线段树分割)
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
int n,m;
struct Node {int op,l,r;Node(){}Node(int op,int l,int r):op(op),l(l),r(r){}
} nn[MAX];
int a[MAX],k;
struct TREE {int l,r;int val,laz;
} tree[MAX<<2];
int len(int cur) {return tree[cur].r - tree[cur].l + 1;
}
void pushup(int cur) {tree[cur].val = tree[cur*2].val + tree[cur*2+1].val;
}
void pushdown(int cur) {if(tree[cur].laz == -1) return ;//如果是0???则??? int tmp = tree[cur].laz;tree[cur].laz = -1;tree[cur*2].val = len(cur*2) * tmp;tree[cur*2+1].val = len(cur*2+1) * tmp;tree[cur*2].laz = tmp;tree[cur*2+1].laz = tmp;
}
void build(int l,int r,int cur,int key) {tree[cur].l = l;tree[cur].r = r;tree[cur].laz = -1;if(l == r) {tree[cur].val = a[l]>=key;return;}int m = (l+r)>>1;build(l,m,cur*2,key);build(m+1,r,cur*2+1,key);pushup(cur);
}
int query(int pl,int pr,int cur) {if(pl <= tree[cur].l && pr >= tree[cur].r) {return tree[cur].val;}pushdown(cur);int res = 0;if(pl <= tree[cur*2].r) res += query(pl,pr,cur*2);if(pr >= tree[cur*2+1].l) res += query(pl,pr,cur*2+1);return res;
}
void update(int pl,int pr,int cur,int val) {if(pl <= tree[cur].l && pr >= tree[cur].r) {tree[cur].laz = val;tree[cur].val = val * len(cur);return;}pushdown(cur);if(pl <= tree[cur*2].r) update(pl,pr,cur*2,val);if(pr >= tree[cur*2+1].l) update(pl,pr,cur*2+1,val);pushup(cur);
}
bool ok(int x) {build(1,n,1,x);for(int i = 1; i<=m; i++) {int l=nn[i].l,r=nn[i].r,op=nn[i].op;int tmp = query(l,r,1);if(tmp == r-l+1 || tmp == 0) continue;if(op == 1) {update(l,l+tmp-1,1,1);update(l+tmp,r,1,0);}else {update(r-tmp+1,r,1,1);update(l,r-tmp,1,0);}} return query(k,k,1) == 1;
}
int main()
{int t;cin>>t;while(t--) {scanf("%d%d",&n,&m);for(int i = 1; i<=n; i++) scanf("%d",a+i);for(int op,x,y,i = 1; i<=m; i++) {scanf("%d%d%d",&op,&x,&y);nn[i] = Node(op,x,y);}scanf("%d",&k);int l = 1,r = n,mid = (l+r)>>1,ans;while(l<=r) {mid = (l+r)>>1;if(ok(mid)) ans=mid,l = mid+1;else r = mid-1;}printf("%d\n",ans);} return 0 ;
}