[Hackerrank题目选做] Sorted Subsegments 二分+线段树

来源:互联网 发布:淘宝产品摄影moxin020 编辑:程序博客网 时间:2024/05/16 06:52

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