[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; 
}

 

posted @ 2018-05-25 00:02  尹吴潇  阅读(149)  评论(0编辑  收藏  举报