题目链接: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; }