洛谷P2827 [NOIP2016 提高组] 蚯蚓 (二叉堆/队列)
容易想到的是用二叉堆来解决,切断一条蚯蚓,其他的都要加上一个值,不妨用一个表示偏移量的delta。
1.取出最大的x,x+=delta;
2.算出切断后的两个新长度,都减去delta和q;
3.delta+=q;
将其他长度都加上q不好实现,我们就把新的两条减去p,相对大小关系不变,最后还原即可。
但这还不是正解:
1 //复杂度mlogn,m过大,要超时 2 #include3 using namespace std; 4 int n,m,q,u,v,t; 5 double p; 6 priority_queue<int,vector<int>,less<int> > que; 7 int delta;//记录偏移量 8 9 int read(){ 10 int x=0,f=1;char c=getchar(); 11 while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} 12 while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar(); 13 return x*f; 14 } 15 16 int main(){ 17 n=read(),m=read(),q=read(),u=read(),v=read(),t=read(); 18 p=(double)u/v; 19 for(int i=1;i<=n;i++){ 20 int x;x=read(); 21 que.push(x); 22 } 23 for(int i=1;i<=m;i++){ 24 int temp; 25 temp=que.top()+delta;que.pop(); 26 int a1=temp*p,a2=temp-a1; 27 a1-=delta+q,a2-=delta+q; 28 delta+=q; 29 que.push(a1),que.push(a2); 30 if(i%t==0) cout< " "; 31 } 32 cout<<endl; 33 int num=0; 34 while(que.size()){ 35 num++; 36 if(num%t==0) 37 cout< " "; 38 que.pop(); 39 } 40 }
进一步分析发现从集合中取出的数是单调递减的,新的两段长度也是单调递减的,这是容易证明的。
所以有三个队列维护:原长度,新产生的长度1,新产生的长度2:
1 //隐晦的单调性 2 //用队列实现,去掉了优先队列的log,所以复杂度是m+nlogn 3 #include4 #define N 7000005 5 using namespace std; 6 bool cmp(const int &a,const int &b){ 7 return a>b; 8 } 9 10 priority_queue<int>ans; 11 int cut1[N],now[N],cut2[N]; 12 int n,m,q,u,v,t; 13 int sigma; 14 double p; 15 int h0,h1,h2; 16 int t0,t1,t2; 17 18 int main(){ 19 scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t); 20 p=(double)u/v;int tmp; 21 for(int i=1;i<=n;i++){ 22 int x;scanf("%d",&x); 23 now[++t0]=x; 24 } 25 h0=h1=h2=1; 26 sort(now+1,now+t0+1,cmp);//对所有蚯蚓从大到小排序 27 int top; 28 for(int i=1;i<=m;++i){ 29 if(h0>t0){if(cut1[h1]>cut2[h2])top=cut1[h1++];else top=cut2[h2++];} 30 else if(now[h0]>=cut1[h1]&&now[h0]>=cut2[h2])top=now[h0],++h0; 31 else if(cut1[h1]>=cut2[h2]&&now[h0]<=cut1[h1])top=cut1[h1],++h1; 32 else top=cut2[h2],++h2; 33 //反正是要找三个队列中的最大值,有很多可以实现的做法 34 top+=sigma; 35 int a1=floor(p*(double)top),a2=top-a1; 36 sigma+=q; 37 a1-=sigma,a2-=sigma; 38 cut1[++t1]=a1,cut2[++t2]=a2; 39 if(i%t==0)printf("%d ",top); 40 } 41 putchar('\n'); 42 for(int i=h0;i<=t0;++i)ans.push(now[i]); 43 for(int i=h1;i<=t1;++i)ans.push(cut1[i]); 44 for(int i=h2;i<=t2;++i)ans.push(cut2[i]); 45 for(int i=1;ans.size();++i){ 46 if(i%t==0)printf("%d ",ans.top()+sigma); 47 ans.pop(); 48 } 49 return 0; 50 }
其他细节的和上一种差不多。