Problem
Description
Input
Output
Sample Input
6 3
1 6 2 5 3 4
0 1 4
1 3 6
0 2 4
3
Sample Output
5
Data Constraint
Solution
正解:线段树+二分。
先二分答案mid,按照mid建一棵线段树(a[i]中如果<mid则标记为0,≥mid则标记为1),将区间[l,r]的数排序,本质是将0放到前面,1放到后面(或将0放到后面,1放到前面)。
实现方法:如果是升序,那么先搜索区间[l,r]中0的个数k,然后将前面的k个数变为0,后(r-l+1)-k个数变成1。用线段树维护。如果是降序就相反。
最后看看第q个数是0还是1。如果是0向前二分,反之向右。
Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define N 100010
using namespace std;
int i,j,q,op,n,m,k,kk,mid,temp;
int tree[N*10][5],a[N],b[N][3];
void build(int s,int l,int r,int mid)
{
if (l==r)
{
if (a[l]>=mid) tree[s][0]=tree[s][1]=1;
else tree[s][0]=tree[s][1]=0;
tree[s][2]=-1;
tree[s][3]=l;
tree[s][4]=r;
return;
}
int wz=(l+r)/2;
build(s*2,l,wz,mid);
build(s*2+1,wz+1,r,mid);
tree[s][1]=tree[s*2][1]+tree[s*2+1][1];
tree[s][2]=-1;
tree[s][3]=tree[s*2][3];
tree[s][4]=tree[s*2+1][4];
}
void count(int s,int l,int r,int x,int y)
{
if (l==x && r==y)
{
k+=tree[s][1];
return;
}
if (tree[s][2]!=-1)
{
tree[s*2][0]=tree[s][2];
tree[s*2][1]=tree[s][2]*(tree[s*2][4]-tree[s*2][3]+1);
tree[s*2][2]=tree[s][2];
tree[s*2+1][0]=tree[s][2];
tree[s*2+1][1]=tree[s][2]*(tree[s*2+1][4]-tree[s*2+1][3]+1);
tree[s*2+1][2]=tree[s][2];
tree[s][2]=-1;
}
int wz=(l+r)/2;
if (y<=wz) count(s*2,l,wz,x,y);
else if (x>wz) count(s*2+1,wz+1,r,x,y);
else
{
count(s*2,l,wz,x,wz);
count(s*2+1,wz+1,r,wz+1,y);
}
}
void change(int s,int l,int r,int x,int y,int z)
{
if (l==x && r==y)
{
tree[s][0]=z;
tree[s][1]=(r-l+1)*z;
tree[s][2]=z;
return;
}
if (tree[s][2]!=-1)
{
tree[s*2][0]=tree[s][2];
tree[s*2][1]=tree[s][2]*(tree[s*2][4]-tree[s*2][3]+1);
tree[s*2][2]=tree[s][2];
tree[s*2+1][0]=tree[s][2];
tree[s*2+1][1]=tree[s][2]*(tree[s*2+1][4]-tree[s*2+1][3]+1);
tree[s*2+1][2]=tree[s][2];
tree[s][2]=-1;
}
int wz=(l+r)/2;
if (y<=wz) change(s*2,l,wz,x,y,z);
else if (x>wz) change(s*2+1,wz+1,r,x,y,z);
else
{
change(s*2,l,wz,x,wz,z);
change(s*2+1,wz+1,r,wz+1,y,z);
}
tree[s][1]=tree[s*2][1]+tree[s*2+1][1];
}
void search(int s,int l,int r,int x)
{
if (l==r)
{
temp=tree[s][0];
return;
}
if (tree[s][2]!=-1)
{
tree[s*2][0]=tree[s][2];
tree[s*2][1]=tree[s][2]*(tree[s*2][4]-tree[s*2][3]+1);
tree[s*2][2]=tree[s][2];
tree[s*2+1][0]=tree[s][2];
tree[s*2+1][1]=tree[s][2]*(tree[s*2+1][4]-tree[s*2+1][3]+1);
tree[s*2+1][2]=tree[s][2];
tree[s][2]=-1;
}
int wz=(l+r)/2;
if (x<=wz) search(s*2,l,wz,x);
else search(s*2+1,wz+1,r,x);
}
bool ok(int mid)
{
int i;
build(1,1,n,mid);
fo(i,1,m)
{
k=0;
count(1,1,n,b[i][1],b[i][2]);
switch (b[i][0])
{
case 0:{
kk=(b[i][2]-b[i][1]+1)-k;
if (kk>0)change(1,1,n,b[i][1],b[i][1]+kk-1,0);
if (b[i][1]+kk<=b[i][2])change(1,1,n,b[i][1]+kk,b[i][2],1);
break;
}
case 1:{
if (k>0)change(1,1,n,b[i][1],b[i][1]+k-1,1);
if (b[i][1]+k<=b[i][2])change(1,1,n,b[i][1]+k,b[i][2],0);
break;
}
}
}
search(1,1,n,q);
if (temp==1) return 1; else return 0;
}
int main()
{
scanf("%d%d",&n,&m);
fo(i,1,n) scanf("%d",&a[i]);
fo(i,1,m) scanf("%d%d%d",&b[i][0],&b[i][1],&b[i][2]);
scanf("%d",&q);
int l=1,r=n;
while (l<r)
{
mid=(l+r)/2;
if (l+1==r)
{
if (ok(r)) l=r;
break;
}
if (ok(mid)) l=mid;else r=mid-1;
}
printf("%d",l);
}
——2016.7.20