题意:
给你n 个数(1~n的排列), m 个操作,
操作1: 将指定区间 升序排序
操作2: 将指定区间降序排列。
最后问你某一个的位置的数是多少?
思路:
神题~~~
没想到这能二分去做。。
直接二分那个数是啥。 然后模拟整个操作。
将比二分的值小的赋为0, 大的赋为1,
然后就是模拟操作
对于升序排序, 直接看看这个区间有多少个0, 多少个1,(线段树维护0的个数即可。)
将前面赋值0 , 后面赋值1即可。
降序同理。
只要看最后那个位置是0 还是1 还是答案即可。
这样 这个问题转换成了 二分 + 线段树区间赋值。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 10;
int n, m, K;
int a[maxn];
struct node{
int op;
int l,r;
void read(){
scanf("%d%d%d",&op ,&l, &r);
}
}p[maxn];
int b[maxn];
struct neode{
int l,r;
int setv;
int sum;
}nod[maxn<<2];
void pushup(int o){
nod[o].sum = nod[o<<1].sum + nod[o<<1|1].sum;
}
void pushdown(int o){
if (nod[o].setv != -1){
int lson = o << 1;
int rson = o << 1 | 1;
nod[lson].setv = nod[rson].setv = nod[o].setv;
if (nod[o].setv == 0){
nod[lson].sum = nod[lson].r - nod[lson].l + 1;
nod[rson].sum = nod[rson].r - nod[rson].l + 1;
}
else {
nod[lson].sum = 0;
nod[rson].sum = 0;
}
nod[o].setv = -1;
}
}
void build(int l,int r,int o){
nod[o].l = l;
nod[o].r = r;
nod[o].setv = -1;
if (l == r){
nod[o].sum = (b[l] == 0 ? 1 : 0);
return ;
}
int m = l + r >> 1;
build(l, m, o<<1);
build(m+1, r, o<<1|1);
pushup(o);
}
void update(int L,int R,int c, int l,int r,int o){
if (L > R) return ;
if (L <= l && r <= R){
nod[o].setv = c;
if (c == 0){
nod[o].sum = r - l + 1;
}
else {
nod[o].sum = 0;
}
return;
}
pushdown(o);
int m = l + r >> 1;
if (m >= L){
update(L,R, c, l, m, o<<1);
}
if (m < R){
update(L, R, c, m+1, r, o<<1|1);
}
pushup(o);
}
int query(int pos,int l,int r,int o){
if (l == r){
if (nod[o].setv != -1) return nod[o].setv;
return nod[o].sum == 0;
}
pushdown(o);
int m = l + r >> 1;
if (m >= pos){
return query(pos, l, m ,o<<1);
}
else {
return query(pos, m+1, r, o<<1|1);
}
}
int Query(int L,int R,int l,int r,int o){
if (L <= l && r <= R){
return nod[o].sum;
}
int m = l + r >> 1;
int ans = 0;
pushdown(o);
if (m >= L){
ans += Query(L,R,l, m, o<<1);
}
if (m < R){
ans += Query(L, R, m+1, r, o<<1|1);
}
return ans;
}
int pos;
void deal(int mid){
for (int i = 1; i <= n; ++i){
if (a[i] == mid) pos = i;
if (a[i] < mid) b[i] = 0;
else if (a[i] > mid) b[i] = 1;
else b[i] = mid;
}
build(1, n, 1);
for (int i = 0; i < m; ++i){
if (p[i].op == 0){
int zero = Query(p[i].l, p[i].r, 1, n, 1);
if (pos >= p[i].l && pos <= p[i].r){
update(p[i].l, p[i].l + zero - 1, 0, 1, n, 1);
update(p[i].l + zero, p[i].l + zero, mid, 1, n, 1);
pos = p[i].l + zero;
update(p[i].l + zero + 1, p[i].r, 1, 1, n, 1);
}
else {
update(p[i].l, p[i].l + zero - 1, 0, 1, n, 1);
update(p[i].l + zero, p[i].r, 1, 1, n, 1);
}
}
else {
int zero = Query(p[i].l, p[i].r, 1, n, 1);
if (pos >= p[i].l && pos <= p[i].r){
update(p[i].r - zero + 1, p[i].r, 0, 1, n, 1);
update(p[i].r - zero , p[i].r - zero, mid, 1, n, 1);
update(p[i].l, p[i].r - zero - 1, 1, 1, n, 1);
pos = p[i].r - zero;
}
else {
update(p[i].r - zero + 1, p[i].r, 0, 1, n, 1);
update(p[i].l, p[i].r - zero, 1, 1, n, 1);
}
}
}
}
void solve(){
int l = 1, r = n;
while(l <= r){
int m = l + r >> 1;
deal(m);
if (pos == K) {
printf("%d\n", m);
return;
}
int val = query(K, 1, n, 1);
if (val == 0){
r = m -1;
}
else if (val == 1) l = m + 1;
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d %d",&n, &m);
for (int i = 1; i <= n; ++i){
scanf("%d", &a[i]);
}
for (int i = 0; i < m; ++i){
p[i].read();
}
scanf("%d",&K);
solve();
}
return 0;
}
/**
1
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
ans = 5;
**/
DZY Loves Sorting
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 547 Accepted Submission(s): 162
Problem Description
a[1..n]. It is a permutation of integers
1∼n.
Now he wants to perform two types of operations:
0lr: Sort
a[l..r] in increasing order.
1lr: Sort
a[l..r] in decreasing order.
After doing all the operations, he will tell you a position
k, and ask you the value of
a[k].
Input
t, denoting the number of testcases.
t testcases follow. For each testcase:
First line contains
n,m.
m is the number of operations.
Second line contains
n space-separated integers
a[1],a[2],⋯,a[n], the initial sequence. We ensure that it is a permutation of
1∼n.
Then
m lines follow. In each line there are three integers
opt,l,r to indicate an operation.
Last line contains
k.
(
1≤t≤50,1≤n,m≤100000,1≤k≤n,1≤l≤r≤n,opt∈{0,1}. Sum of
n in all testcases does not exceed
150000. Sum of
m in all testcases does not exceed
150000)
Output
a[k] after performing all m operations.
Sample Input
1 6 3 1 6 2 5 3 4 0 1 4 1 3 6 0 2 4 3
Sample Output
Hint
Source
Recommend
wange2014 | We have carefully selected several similar problems for you: 6107 6106 6105 6104 6103
Submit |
Discuss |