[国家集训队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 }
话说这份代码跑得还挺快,哈哈……
写题过程中出了两个脑残错误,两个多小时就这么搭进去了……
1.如果序列长度为偶数,按题意中位数应为中间的两个数中较大的那个,然而我一开始读成了较小的那个,然后就死活弄不清脑子一片混乱……
2.注意到求最大后缀和最后一句if(s<=mid)了没……一开始写成了if(t<=mid),然后澄清完了题意还各种跟暴力拍不上,我特么都快崩溃了……后来发现是这个脑残错误,我只想说: $%*&$^%&#$%!@&#@^&*!%$^#@%*……
看看这惨烈的提交记录……
下次写题一定要先澄清题意……脑残怎么治啊……
233333333