题目链接:https://www.hackerrank.com/challenges/sorted-subsegments

题目大意:给定n,q,k和一个大小为n的数组A,共有q组操作,每组操作给定l,r,要求将A[l]...A[r]按照升序排序,q组操作后求A[k]的值。(n,q<=7.5*10^4)

Part 1  骗分

菜鸡并不会这样的神题水题,只能按照万年不变的骗分策略去小数据暴力,大数据贪心

可是-------满分80pts,就这样一个400B的代码骗了43.87pts!(骗分的力量是无穷的,滑稽.jpg) 

#include <bits/stdc++.h>
using namespace std;
int a[75005],n,q,k,i,l,r;
int main (){
	scanf ("%d%d%d",&n,&q,&k);
	for (i=0;i<n;i++)
	{scanf ("%d",&a[i]);}
	int ll,rr;
	l=0;r=0;
    for (i=0;i<q;i++)
	{ll=l;rr=r;
	scanf ("%d%d",&l,&r);
	if (!(l>=ll&&r<=rr)) {sort(a+l,a+r+1);}
	if ((double)(clock())/CLOCKS_PER_SEC>1.8)
	{sort(a,a+n);break;}
    }
	printf ("%d",a[k]);
	return 0;
}



Part 2 标算
然后,失去了思考能力的菜鸡博主打开了editorial,再次被教做人.
题解: 设bi为q次操作后形成的数组,ci为01数组,对于常数x,ci=(bi>=x).
然后考虑二分答案x,这样x就成为了一个不变量,
对于每次操作[l,r],考虑操作后对于c数组的影响,
首先,因为该区间内的数字不变,所以0,1的数量不变,
而且,一个显然的性质是-----一次操作后,0全部移到了左边,1全部移到了右边(因为数组变得有序化了),
这样,通过线段树维护序列c,通过判断ck是否为1进行二分,从而O(nlognlog(Maxn-Minn))时间内完成对a[k]的计算。
大体思想:若要维护具体数值,很难从O(n^2logn)的暴力做法中取得突破,
所以考虑用1个log的代价化具体数值为01变量,维护01数组表示大小关系从而做到更优秀的复杂度。
AC_Code: (这题可能需要卡常TAT)

#include <bits/stdc++.h>
#define inf 1000000000
#define ls pos<<1
#define rs pos<<1|1
using namespace std;
struct node
{int l,r,siz,tag,p;
}t[300005];
int a[75005],l[75005],r[75005],c[75005];
int n,q,k;
void build(int pos,int l,int r)
{t[pos].l=l,t[pos].r=r,t[pos].tag=0,t[pos].siz=r-l+1;
if (l==r) {t[pos].p=c[l];return;}
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
t[pos].p=t[ls].p+t[rs].p;
}
inline void tag_down(int pos)
{if (t[pos].tag!=0)
{t[ls].tag=t[rs].tag=t[pos].tag;
if (t[pos].tag==-1)
{t[ls].p=t[rs].p=0;}
else
{t[ls].p=t[ls].siz,t[rs].p=t[rs].siz;}
t[pos].tag=0;
}
}
int qr(int pos,int l,int r)
{if (t[pos].l==l&&t[pos].r==r) {return t[pos].p;}
tag_down(pos);
int mid=(t[pos].l+t[pos].r)>>1;
if (r<=mid) return qr(ls,l,r);
if (l>=mid+1) return qr(rs,l,r);
return qr(ls,l,mid)+qr(rs,mid+1,r);
}
void modify(int pos,int l,int r,int d)
{if (t[pos].l==l&&t[pos].r==r)
{if (!d) {t[pos].p=0,t[pos].tag=-1;}
else {t[pos].p=t[pos].siz,t[pos].tag=1;}
return;
}
tag_down(pos);
int mid=(t[pos].l+t[pos].r)>>1;
if (r<=mid)
{modify(ls,l,r,d);}
else
{if (l>=mid+1) {modify(rs,l,r,d);}
else {modify(ls,l,mid,d),modify(rs,mid+1,r,d);}
}
t[pos].p=t[ls].p+t[rs].p;
}
int main (){
	int i,j;
	int minn=inf,maxn=-inf;
	scanf ("%d%d%d",&n,&q,&k);
	for (i=1;i<=n;i++)
	{scanf ("%d",&a[i]);
	if (a[i]<minn) {minn=a[i];}
	if (a[i]>maxn) {maxn=a[i];}
	}
	k++;
	for (i=1;i<=q;i++)
	{scanf ("%d%d",&l[i],&r[i]);
	l[i]++,r[i]++;
	}
	int lc=minn,rc=maxn;
	while (lc<=rc)
	{int mid=(lc+rc)>>1;
	for (i=1;i<=n;i++)
	{if (a[i]>=mid) {c[i]=1;}
	else {c[i]=0;}
	}
	build(1,1,n);
	for (i=1;i<=q;i++)
	{int num=qr(1,l[i],r[i]);
	if (l[i]<=r[i]-num) {modify(1,l[i],r[i]-num,0);}
	if (num>0) {modify(1,r[i]-num+1,r[i],1);}
	}
	int t=qr(1,k,k);
	if (t) {lc=mid+1;}
	else {rc=mid-1;}
	}
	printf ("%d\n",rc);
	return 0;
}