P2824 [HEOI2016/TJOI2016]排序
贴个链接
题意是给一个长度为n的序列,有m次操作;每次操作是:
0 l r 把 l ~ r 区间按递增排序
1 l r 把 l ~ r 区间按递减排序
最后为pos 位置上的值是多少。
这个怎么做?
按他的操作没法完成排序,(是我不会)
但是,可以考虑二分一个答案。
现在问题相当于是给一个值问经过上次操作后的值比这个值大还是比这个值小。来确定二分边界的变化。
?把比mid小的变为0,把mid大的变为1.
这样一来,排序操作就是查询这个区间有多少个1,然后把前面一段变成1,后面一段变成0就好,就是简单的线段树。
最后查询这个位置上的值是0还是1 是1的话证明答案比它大,否则比他小。
所以复杂度nlognlogn
代码
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <string>
#include <queue>
#include <cstring>
#include <stack>
#include <map>
#include <bitset>
#include <math.h>
#include <set>
#include <ctime>
#include <unordered_set>
#include <climits>
using namespace std;
typedef long long ll;
typedef pair<int,ll> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef unsigned long long ull;
typedef unordered_set<int>::iterator sit;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void tempwj(){freopen("P3380_2.in","r",stdin);freopen("hash.out","w",stdout);}
ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){a %= mod;ll ans = 1;while(b > 0){if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans % mod;}
struct cmp{bool operator()(const pii & a, const pii & b){return a.second > b.second;}};
int lb(int x){return x & -x;}
// friend bool operator < (Node a,Node b) 重载
// 8388607
const int inf = INT_MAX;
const double esp = 1e-9;
const ll INF = 0x3f3f3f3f3f3f;
const ll mod = 1e9+7;
const int maxn = 1e5 + 5;
const int M = 2e6+5;
int a[maxn];
int b[maxn];
int c[maxn];
int n,m;
struct Node
{
int l,r,num,tag;
}node[maxn << 2];
void build(int l,int r,int no)
{
node[no].tag = -1;
node[no].l = l;
node[no].r = r;
node[no].num = 0;
if(l == r)
{
node[no].num = c[l];
return;
}
int mid = l +r >> 1;
build(l,mid,no<<1);
build(mid+1,r,no<<1|1);
node[no].num = node[no<<1].num + node[no<<1|1].num;
}
void change(int no,int num)
{
node[no].num = (node[no].r - node[no].l + 1) * num;
node[no].tag = num;
}
void down(int no)
{
change(no<<1,node[no].tag);
change(no<<1|1,node[no].tag);
node[no].tag = -1;
}
void update(int l,int r,int no,int num)
{
if(node[no].l > r|| node[no].r < l)
return;
if(node[no].l >=l && node[no].r <= r)
{
change(no,num);
return;
}
if(node[no].tag != -1)
down(no);
update(l,r,no<<1,num);
update(l,r,no<<1|1,num);
node[no].num = node[no<<1].num + node[no<<1|1].num;
}
int query(int l,int r,int no)
{
if(node[no].l > r || node[no].r < l)
return 0;
if(node[no].l >= l && node[no].r <= r)
return node[no].num;
if(node[no].tag != -1)
down(no);
return query(l,r,no<<1) + query(l,r,no<<1|1);
}
struct Que
{
int f,x,y;
}Q[maxn];
int k;
bool solve(int x)
{
// printf("%d\n",x);
for (int i = 1; i <= n; i ++ )
{
if(a[i] >= x)
c[i] = 1;
else
c[i] = 0;
// printf("%d ",c[i]);
}
// printf("\n");
build(1,n,1);
for (int i= 1; i <= m; i ++ )
{
int s= 0 ;
if(Q[i].f == 1) // 降序 1111111 00000
{
s = query(Q[i].x,Q[i].y,1);
update(Q[i].x,Q[i].x + s - 1,1,1);
update(Q[i].x + s,Q[i].y,1,0);
}
else // 00001111
{
s = query(Q[i].x,Q[i].y,1);
update(Q[i].x,Q[i].y - s,1,0);
update(Q[i].y - s + 1,Q[i].y,1,1);
}
// printf("%d %d %d\n",Q[i].x,Q[i].y,s);
}
int s = query(k,k,1);
return s == 1;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1 ; i <= n; i ++ )
{
scanf("%d",&a[i]);
b[i] = a[i];
}
for(int i =1 ; i <= m; i ++ )
{
scanf("%d%d%d",&Q[i].f,&Q[i].x,&Q[i].y);
}
sort(b + 1, b + 1 + n);
// int k;
scanf("%d",&k);
int l = 1, r = n;
while(l < r)
{
int mid = l +r + 1>> 1;
if(solve(mid))
l = mid;
else
r = mid - 1;
}
printf("%d\n",b[l]);
}