noi 2010 超级钢琴 划分树

题意:小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐。 这架超级钢琴可以弹奏出n个音符,编号为1至n。第i个音符的美妙度为Ai,其中Ai可正可负。 一个“超级和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R。我们定义超级和弦的美妙度为其包含的所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。 小Z决定创作一首由k个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由k个不同的超级和弦组成。我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最大值是多少。

 

思路:划分树+priority_queue

 

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<cstdio>
  5 #include<queue>
  6 #include<algorithm>
  7 using namespace std;
  8 #define MAXN 510001
  9 struct node
 10 {
 11     int val[MAXN];
 12     int num[MAXN];
 13 }tree[22];
 14 struct heap
 15 {
 16     int num,k,val;
 17 };
 18 priority_queue<heap> Q;
 19 int n,m,L,R;
 20 int a[MAXN],sorted[MAXN],sum[MAXN];
 21 long long ans=0;
 22 bool operator < (const heap &A,const heap &B)
 23 {
 24     return A.val<B.val;
 25 }
 26 void build(int t,int left,int right)
 27 {
 28     if(left==right)
 29         return ;
 30     int mid=(left+right)/2;
 31     int i,isame=0,k1=left-1,k2=mid;
 32     for(i=left;i<=right;i++)
 33         if(tree[t].val[i]<sorted[mid])
 34             isame++;
 35     for(i=left;i<=right;i++)
 36     {
 37         if(tree[t].val[i]<sorted[mid])
 38             tree[t+1].val[++k1]=tree[t].val[i];
 39         else if(tree[t].val[i]>sorted[mid])
 40             tree[t+1].val[++k2]=tree[t].val[i];
 41         else if(isame<mid-left+1)
 42         {
 43             tree[t+1].val[++k1]=tree[t].val[i];
 44             isame++;
 45         }
 46         else
 47         {
 48             tree[t+1].val[++k2]=tree[t].val[i];
 49             isame++;
 50         }
 51         tree[t].num[i]=k1+1-left+tree[t].num[left-1];
 52     }
 53     build(t+1,left,mid);
 54     build(t+1,mid+1,right);
 55 }
 56 int search(int left,int right,int l,int r,int k,int t)
 57 {
 58     if(left==right)
 59        return tree[t].val[left];
 60     int mid=(left+right)/2;
 61     int temp=tree[t].num[r]-tree[t].num[l-1];
 62     int x=tree[t].num[l-1]-tree[t].num[left-1];
 63     int y=tree[t].num[r]-tree[t].num[left-1];
 64     if(temp>=k)
 65         return search(left,mid,left+x,left+y-1,k,t+1);
 66     else
 67         return search(mid+1,right,mid+l-left+1-x,mid+r-left+1-y,k-temp,t+1);
 68 }
 69 void solve()
 70 {
 71     int i;
 72     for(i=L+1;i<=n;i++)
 73     {
 74         heap temp;
 75         
 76         temp.val=sum[i]-search(1,n,max(i-R,1),max(i-L,1),1,1);
 77         temp.num=i;
 78         temp.k=1;
 79         Q.push(temp);
 80     }
 81     for(i=1;i<=m;i++)
 82     {
 83         heap temp=Q.top();
 84         Q.pop();
 85         ans+=temp.val;
 86         int x,y,t;
 87         t=temp.num;
 88         x=max(t-R,1); y=max(t-L,1);
 89         if(y-x+1<=temp.k)
 90             continue;
 91         temp.val=sum[t]-search(1,n,x,y,temp.k+1,1);
 92         temp.k++;
 93         Q.push(temp);
 94     }
 95     printf("%lld\n",ans);
 96 }
 97 int main()
 98 {
 99     memset(tree,0,sizeof(tree));
100     sorted[1]=sum[1]=0;
101     scanf("%d%d%d%d",&n,&m,&L,&R);
102     int i;
103     for(i=1;i<=n;i++)
104     {
105         scanf("%d",a+i);
106         sum[i+1]=sum[i]+a[i];
107         sorted[i+1]=tree[1].val[i+1]=sum[i+1];
108     }
109     n++;
110     sort(sorted+1,sorted+n+1);
111     build(1,1,n);
112     solve();
113     return 0;
114 }

posted on 2012-07-11 21:24  myoi  阅读(484)  评论(0编辑  收藏  举报

导航