[NOI2010]超级钢琴
题解:
虽然这题挺简单的 但在实现上还是有一些问题
首先变前缀和
然后对每个点维护一颗线段树,表示x-l,x-r
这个用主席树维护就好了
另外的思路就跟那个两个串,取k大一样
用堆对每个右节点维护一下就可以了
然后这样就是nlogn的
在实现中遇到的一些问题
1.由于不太用堆,发现cmp写的是反的
2.这个读入要开到1<<25 不然是要挂的 也就是读入2e6个字符 我并不是很懂为什么要开这么大
不过经验告诉我小了他会直接卡住 所以这个还得注意一下
3.等这个数,被删了再删它,不要用了再删
这样能快2/3的常数
空间也是40*n的 不然是60*n的
另外这个不开o2并不能跑过最后一个点,我觉得应该手写一下堆就可以了
但是在现在这种都是氧气的比赛里(noip除外)并没有什么必要啊
网上的做法是用st表做到询问o(1)
对于删除,它直接把一个区间分裂成两个区间,然后就可以了
这样常数比我低了很多
我开o2总时间也要3000ms+
看了一下1000ms以内的应该都是st的而且手写了堆就没看了
我觉得好像也压不了时间了
#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) #define ll long long char ss[1<<25],*A=ss,*B=ss; IL char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<25,stdin),A==B)?EOF:*A++;} template<class T>void read(T&x){ rint f=1,c;while(c=gc(),c<48||57<c)if(c=='-')f=-1;x=c^48; while(c=gc(),47<c&&c<58)x=(x<<3)+(x<<1)+(c^48);x*=f; } const int N=5.1e5; const int INF=1e9; int max1[N*40],max2[N*40],ls[N*40],rs[N*40]; int n,k,l,r,a[N],sum[N],root[N],cnt; struct re{ int a,b,c; }; struct cmp { bool operator () (re x,re y) { return(x.a<y.a); } }; priority_queue<re,vector<re>,cmp> pq; #define mid ((h+t)/2) IL void updata(int x) { if (max1[ls[x]]<max1[rs[x]]) { max2[x]=max2[ls[x]],max1[x]=max1[ls[x]]; } else { max2[x]=max2[rs[x]],max1[x]=max1[rs[x]]; } } void insert(int last,int &x,int h,int t,int pos,int k) { x=++cnt; ls[x]=ls[last]; rs[x]=rs[last]; if (h==t) { max1[x]=k; max2[x]=h; return; } if (pos<=mid) insert(ls[last],ls[x],h,mid,pos,k); else insert(rs[last],rs[x],mid+1,t,pos,k); updata(x); } re query(int x,int h,int t,int h1,int t1) { if (x==0) return((re){INF,0}); if (h1<=h&&t<=t1) return((re){max1[x],max2[x]}); re ans1={INF,0},ans2={INF,0}; if (h1<=mid) ans1=query(ls[x],h,mid,h1,t1); if (mid<t1) ans2=query(rs[x],mid+1,t,h1,t1); if (ans1.a<ans2.a) return(ans1); else return(ans2); } int main() { freopen("2.in","r",stdin); freopen("2.out","w",stdout); read(n); read(k); read(l); read(r); rep(i,1,n) read(a[i]),sum[i]=sum[i-1]+a[i]; insert(root[1],root[1],0,n,0,0); rep(i,1,n-1) { insert(root[i],root[i+1],0,n,i,sum[i]); } rep(i,1,n) { re x={INF,0}; if (i-l>=0) x=query(root[i],0,n,max(i-r,0),i-l); if (x.a!=INF) pq.push((re){sum[i]-x.a,i,x.b}); } ll ans=0; rep(i,1,k) { re xx=pq.top(); pq.pop(); ans+=1ll*xx.a; insert(root[xx.b],root[xx.b],0,n,xx.c,INF); re x={INF,0}; if(xx.b-l>=0) x=query(root[xx.b],0,n,max(xx.b-r,0),xx.b-l); if (x.a!=INF) pq.push((re){sum[xx.b]-x.a,xx.b,x.b}); } printf("%lld",ans); return 0; }