[国家集训队2012]middle(陈立杰)

我是萌萌的传送门

我是另一个萌萌的传送门

脑残错误毁一下午……

其实题解早就烂大街了,然而很久之前我只知道是二分答案+主席树却想不出来这俩玩意儿怎么一块儿用的……今天又翻了几篇题解才恍然大悟,是把权值排序之后依次插入序列,用主席树维护连续和……(我菜爆了……= =)

还是讲讲大体思路吧,首先二分答案M,把>=M的元素标为1,<M的标为-1,然后判定满足条件的最大子串和是否>=0,是则说明判定标准可行,否则不可行,调整下一次二分即可。但是直接暴力标记肯定会T,所以尝试对所有判定标准维护线段树来求最大子串和,然而内存开不下……考虑到如果把元素依次插入的话每次只会修改一个值,那么就把元素排序后依次插入线段树中,可持久化压内存即可。

一点细节:

鉴于子序列中间那段是肯定会用到的,所以直接拆成三段,前一段求最大后缀和,中间直接求和,后一段求最大前缀和,合并即可。因为最大前缀/后缀和是非严格最大(可以一个都不选),所以需要把b和c归到中间那段(保证一定会用上)。

贴个bzoj的代码:

  1 /**************************************************************
  2     Problem: 2653
  3     User: hzoier
  4     Language: C++
  5     Result: Accepted
  6     Time:936 ms
  7     Memory:101108 kb
  8 ****************************************************************/
  9  
 10 #include<cstdio>
 11 #include<cstring>
 12 #include<algorithm>
 13 using namespace std;
 14 const int maxn=20010;
 15 struct node{
 16     int sum,prefix,suffix;
 17     node *lc,*rc;
 18     void refresh(){
 19         sum=lc->sum+rc->sum;
 20         prefix=max(lc->prefix,lc->sum+rc->prefix);
 21         suffix=max(rc->suffix,rc->sum+lc->suffix);
 22     }
 23 }null[maxn<<8],*ptr=null;
 24 struct A{
 25     int d,id;
 26     bool operator<(const A &a)const{return d<a.d;}
 27 }a[maxn];
 28 void build(int,int,node*&);
 29 void modify(int,int,node*&,node*&);
 30 void qsum(int,int,node*);
 31 void qprefix(int,int,node*);
 32 void qsuffix(int,int,node*);
 33 node *root[maxn];
 34 int n,m,x,d,s,t,q[5],tmp,sum,ans,lastans=0,L,R,M;
 35 int main(){
 36     null->lc=null->rc=null;
 37     null->sum=null->prefix=null->suffix=0;
 38     scanf("%d",&n);
 39     fill(root,root+n+1,(node*)null);
 40     build(1,n,root[0]);
 41     for(int i=1;i<=n;i++){
 42         scanf("%d",&a[i].d);
 43         a[i].id=i;
 44     }
 45     sort(a+1,a+n+1);
 46     for(int i=1;i<=n;i++){
 47         x=a[i].id;
 48         modify(1,n,root[i],root[i-1]);
 49     }
 50     scanf("%d",&m);
 51     while(m--){
 52         for(int i=0;i<4;i++){
 53             scanf("%d",&q[i]);
 54             q[i]+=lastans;q[i]%=n;q[i]++;
 55         }
 56         sort(q,q+4);
 57         L=1;R=n;
 58         while(L<=R){
 59             M=(L+R)>>1;
 60             ans=0;
 61             s=q[1];t=q[2];
 62             qsum(1,n,root[M-1]);
 63             s=q[0];t=q[1]-1;
 64             sum=tmp=0;
 65             if(s<=t)qsuffix(1,n,root[M-1]);
 66             ans+=sum;
 67             s=q[2]+1;t=q[3];
 68             sum=tmp=0;
 69             if(s<=t)qprefix(1,n,root[M-1]);
 70             ans+=sum;
 71             if(ans>=0)L=M+1;
 72             else R=M-1;
 73         }
 74         printf("%d\n",lastans=a[R].d);
 75     }
 76     return 0;
 77 }
 78 void build(int l,int r,node *&rt){
 79     rt=++ptr;
 80     rt->sum=rt->prefix=rt->suffix=r-l+1;
 81     if(l==r){
 82         rt->lc=rt->rc=null;
 83         return;
 84     }
 85     int mid=(l+r)>>1;
 86     build(l,mid,rt->lc);
 87     build(mid+1,r,rt->rc);
 88 }
 89 void modify(int l,int r,node *&rt,node *&pr){
 90     *(rt=++ptr)=*pr;
 91     if(l==r){
 92         rt->sum=-1;
 93         rt->prefix=rt->suffix=0;
 94         return;
 95     }
 96     int mid=(l+r)>>1;
 97     if(x<=mid)modify(l,mid,rt->lc,pr->lc);
 98     else modify(mid+1,r,rt->rc,pr->rc);
 99     rt->refresh();
100 }
101 void qsum(int l,int r,node *rt){
102     if(s<=l&&t>=r){
103         ans+=rt->sum;
104         return;
105     }
106     int mid=(l+r)>>1;
107     if(s<=mid)qsum(l,mid,rt->lc);
108     if(t>mid)qsum(mid+1,r,rt->rc);
109 }
110 void qprefix(int l,int r,node *rt){
111     if(s<=l&&t>=r){
112         sum=max(sum,tmp+rt->prefix);
113         tmp+=rt->sum;
114         return;
115     }
116     int mid=(l+r)>>1;
117     if(s<=mid)qprefix(l,mid,rt->lc);
118     if(t>mid)qprefix(mid+1,r,rt->rc);
119 }
120 void qsuffix(int l,int r,node *rt){
121     if(s<=l&&t>=r){
122         sum=max(sum,tmp+rt->suffix);
123         tmp+=rt->sum;
124         return;
125     }
126     int mid=(l+r)>>1;
127     if(t>mid)qsuffix(mid+1,r,rt->rc);
128     if(s<=mid)qsuffix(l,mid,rt->lc);
129 }
View Code

话说这份代码跑得还挺快,哈哈……

写题过程中出了两个脑残错误,两个多小时就这么搭进去了……

1.如果序列长度为偶数,按题意中位数应为中间的两个数中较大的那个,然而我一开始读成了较小的那个,然后就死活弄不清脑子一片混乱……

2.注意到求最大后缀和最后一句if(s<=mid)了没……一开始写成了if(t<=mid),然后澄清完了题意还各种跟暴力拍不上,我特么都快崩溃了……后来发现是这个脑残错误,我只想说: $%*&$^%&#$%!@&#@^&*!%$^#@%*……

看看这惨烈的提交记录……

下次写题一定要先澄清题意……脑残怎么治啊……

posted @ 2017-01-09 17:44  AntiLeaf  阅读(307)  评论(0编辑  收藏  举报