P2048 [NOI2010]超级钢琴

无关:突然感觉之前的码风调代码不太方便,还是稍微改一下吧,毕竟现在竞赛的代码写出来还是要给自己看的...


 

这道题,显然确定了一个端点之后这个端点对应的区间和的最大值是定的,很容易想到用ST表维护一个前缀和最大值

然后再维护一个大根堆,记录每个合法最大值区间

在每一个状态时,堆顶元素一定是最优解,所以每次取堆顶元素即可

但是把堆顶元素取出来之后,之后最优解还有可能在当前堆顶的集合中的子集里产生,所以还需要把当前堆顶有可能产生的其他贡献丢到堆里

设堆顶元素在位置pos处取到最优解的情况,那么因为两个和弦不能相同,可能的新的贡献的右端点只有可能在$[l,pos-1]$和$[pos+1,r]$中取到

把这两个区间也丢进去维护就好了

 1 //hgs AK IOI,IMO,ICHO,IPHO
 2 #include<bits/stdc++.h>
 3 #define int long long
 4 #define writeln(x)  write(x),puts("")
 5 #define writep(x)   write(x),putchar(' ')
 6 using namespace std;
 7 inline int read(){
 8     int ans=0,f=1;char chr=getchar();
 9     while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();}
10     while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();}
11     return ans*f;
12 }void write(int x){
13     if(x<0) putchar('-'),x=-x;
14     if(x>9) write(x/10);
15     putchar(x%10+'0');
16 }const int M = 5E5+5;
17 int a[M],s[M],st[M][21],n,m,sl,sr,lg2[M]={-1},bin[21]={1};
18 inline int max(int x,int y){return ((x>y)?(x):(y));}
19 inline int min(int x,int y){return ((x>y)?(y):(x));}
20 inline int chkmax(int x,int y){return (s[x]>s[y])?(x):(y);}
21 inline void Pre()
22 {
23     for(int i=1;i<=20;i++)
24         bin[i]=bin[i-1]<<1;
25     for(int i=1;i<=n;i++)
26         lg2[i]=lg2[i>>1]+1,
27         st[i][0]=i;
28     for(int j=1;j<=20;j++)
29         for(int i=1;i+bin[j]-1<=n;i++)
30             st[i][j]=chkmax(st[i][j-1],st[i+bin[j-1]][j-1]);
31 }
32 inline int Query(int l,int r)
33 {
34     return chkmax(st[l][lg2[r-l+1]],st[r-bin[lg2[r-l+1]]+1][lg2[r-l+1]]);
35 }
36 struct P
37 {
38     int x,l,r;
39     inline int Calc()const
40     {
41         return s[Query(l,r)]-s[x-1];
42     }
43     friend bool operator<(const P&a,const P&b)
44     {
45         return a.Calc()<b.Calc();
46     }
47 };
48 priority_queue<P>q;
49 inline P Make(int x,int l,int r)
50 {
51     r=min(r,n);
52     return (P){x,l,r};
53 }
54 inline void Split(const P&x)
55 {
56     P t1,t2;
57     int pos=Query(x.l,x.r);
58     if(x.l!=pos)q.push(Make(x.x,x.l,pos-1));
59     if(x.r!=pos)q.push(Make(x.x,pos+1,x.r));
60 }
61 signed main()
62 {
63     n=read(),m=read(),sl=read(),sr=read();
64     for(int i=1,x;i<=n;i++)
65         s[i]=read(),s[i]+=s[i-1];
66     Pre();
67     for(int i=1;i+sl-1<=n;i++)
68         q.push(Make(i,i+sl-1,i+sr-1));
69     register int ans(0);
70     while(m--)
71     {    
72         P now=q.top();
73         q.pop();
74         ans+=now.Calc();
75         Split(now);
76     }cout<<ans;
77     return 0;
78 }

 

posted @ 2019-10-31 21:09  zheng_liwen  阅读(223)  评论(0编辑  收藏  举报
/*去广告*/