题意:
给一个1-n的全排列,q次操作,每次操作排序一段区间(升序或降序都有可能),最后问第k个位置是多少。
n<=100000,q<=100000。
题解:
显然,此题直接模拟效率为O(nqlogn),过不去。
我们无法做到快速的排序一段数值在[1,n]范围内的区间,但是我们可以用logn的时间做到排序一段数值在[0,1]的区间。
方法很简单,只需要用线段树求出该区间有多少个0和1,然后前一部分赋值为0(或1),后一部分赋值为1(或0)即可。
由于这题只需要求出某一个位置的值,所以不需要确切的知道每一个位置的值。
考虑二分一个答案,判断这个位置的值是否大于它。判断方法就是把大于mid的值设为1,小于等于mid的设为0,然后直接模拟排序即可。
感觉还是二分不那么容易想到。
#include#include #include using namespace std; int n,m,a[100002],qq,mid; typedef struct{ bool u; int l,r; }P; typedef struct{ int sum0,f; }PP; P q[100002]; PP p[400002]; void build(int root,int begin,int end){ p[root].f=-1; if (begin==end) { p[root].sum0=(a[begin]<=mid);return; } int mid=(begin+end)/2; build(root*2,begin,mid);build(root*2+1,mid+1,end); p[root].sum0=p[root*2].sum0+p[root*2+1].sum0; } void pushdown(int root,int begin,int mid,int end){ if (p[root].f==0) { p[root*2].sum0=mid-begin+1;p[root*2+1].sum0=end-mid; p[root*2].f=p[root*2+1].f=0; p[root].f=-1; } if (p[root].f==1) { p[root*2].sum0=p[root*2+1].sum0=0; p[root*2].f=p[root*2+1].f=1; p[root].f=-1; } } void gx0(int root,int begin,int end,int begin2,int end2){ if (begin>end2 || end return; if (begin>=begin2 && end<=end2) { p[root].sum0=end-begin+1;p[root].f=0; return; } int mid=(begin+end)/2;pushdown(root,begin,mid,end); gx0(root*2,begin,mid,begin2,end2);gx0(root*2+1,mid+1,end,begin2,end2); p[root].sum0=p[root*2].sum0+p[root*2+1].sum0; } void gx1(int root,int begin,int end,int begin2,int end2){ if (begin>end2 || end return; if (begin>=begin2 && end<=end2) { p[root].sum0=0;p[root].f=1; return; } int mid=(begin+end)/2;pushdown(root,begin,mid,end); gx1(root*2,begin,mid,begin2,end2);gx1(root*2+1,mid+1,end,begin2,end2); p[root].sum0=p[root*2].sum0+p[root*2+1].sum0; } int cx(int root,int begin,int end,int begin2,int end2){ if (begin>end2 || end return 0; if (begin>=begin2 && end<=end2)return p[root].sum0; int mid=(begin+end)/2;pushdown(root,begin,mid,end); return cx(root*2,begin,mid,begin2,end2)+cx(root*2+1,mid+1,end,begin2,end2); } bool chaxun(int root,int begin,int end,int wz){ if (begin==end)return !(p[root].sum0==1); int mid=(begin+end)/2;pushdown(root,begin,mid,end); if (wz<=mid)return chaxun(root*2,begin,mid,wz); else return chaxun(root*2+1,mid+1,end,wz); } bool pd(){ build(1,1,n); for (int i=1;i<=m;i++) if (!q[i].u) { int l=q[i].r-q[i].l+1,d0=cx(1,1,n,q[i].l,q[i].r);int d1=l-d0; gx0(1,1,n,q[i].l,q[i].l+d0-1);gx1(1,1,n,q[i].l+d0,q[i].r); } else { int l=q[i].r-q[i].l+1,d0=cx(1,1,n,q[i].l,q[i].r);int d1=l-d0; gx1(1,1,n,q[i].l,q[i].l+d1-1);gx0(1,1,n,q[i].l+d1,q[i].r); } return chaxun(1,1,n,qq); } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++)scanf("%d",&a[i]); for (int i=1;i<=m;i++)scanf("%d%d%d",&q[i].u,&q[i].l,&q[i].r); scanf("%d",&qq); int lef=1,righ=n; while(lef<righ) { mid=(lef+righ)/2; if (pd()==0)righ=mid;else lef=mid+1; } printf("%d\n",lef); return 0; }