이름
생각
간단한 아이디어는 각각의 모든 지렁이 플러스와 마찬가지로 (다시 힙으로 두 부분으로 잘라 그 최대 복용, 직접 긍정을 유지하기 위해 힙을 사용하는 것입니다 \ (q를 \) ,이 지렁이 마이너스의 새로운 세대로 볼 수있다 \ (시간 * Q \) , 그리고 마지막으로 다시에 플러스, \ (시간 \) 즉, 몇 초)하지만,이 방법은 이루어집니다 \ (O (N + m) 로그 (N + m) \) , 이상 할 수 없습니다
분석은 단순 찾을 수 후, 즉 두 부분을 각각 단조 감소 배열로 절단하는 경우
증명은 매우 간단, 지렁이 길이의 첫 번째 컷하자 \ (LEN1의 \) 절단에서 절단 한 후, \을 (LEN1 \) 이 시간 길이 \ (LEN2 \) , 다음이 \ (LEN2 \) \ (\ LEQ \) \ (LEN1 \) , 즉 그들은 양을 증가 동일한 경우 성장 시간 만 절단 길이하고있다 \ (LEN2 + C \) \ (\ 당량 \) \ (LEN1 + C \) 일정 설정
그러므로 세 개의 어레이 (큐)로 나누어, 각각 첫번째, 두번째 (칼로 절단 후의) 초기 증착 지렁이는 초기 순서는 내림차순 지렁이는 제 배열 후에 잘라낼 수 있도록 두 어레이는 내림차순을 충족 할 수 있도록 뒤에 큐로 지렁이 즉, 지렁이 세 HOL 큐에서 최대 값의 최대 값을 고려
두 번째 질문의 경우, 세 개의 큐는 일종의 병합
시간 복잡도는 () O (nlogn + m의 \ \)
#include<bits/stdc++.h>
#define N 100005
#define M 7000005
using namespace std;
int n,m,q,u,v,t;
int a[3][M],top[3];
int b[N+M],c[N+M];
template <class T>
void read(T &x)
{
char c;int sign=1;
while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
}
bool cmp(int a,int b) {return a>b;}
int main()
{
read(n);read(m);read(q);
read(u);read(v);read(t);
for(register int i=1;i<=n;++i) read(a[0][i]);
a[0][0]=n;
top[0]=top[1]=top[2]=1;
sort(a[0]+1,a[0]+n+1,cmp);
for(register int i=1;i<=m;++i)
{
int maxx=(top[0]>n);
if(a[maxx][top[maxx]]<a[1][top[1]]&&top[1]<=a[1][0]) maxx=1;
if(a[maxx][top[maxx]]<a[2][top[2]]&&top[2]<=a[2][0]) maxx=2;
int len=a[maxx][top[maxx]++]+(i-1)*q;
int L=(long long)u*len/v;
int R=len-L;
a[1][++a[1][0]]=L-q*i;
a[2][++a[2][0]]=R-q*i;
if(i%t==0) printf("%d ",len);
}
printf("\n");
int l=top[0],r=top[1];
while(l<=a[0][0]&&r<=a[1][0])
{
if(a[0][l]>a[1][r]) b[++b[0]]=a[0][l++];
else b[++b[0]]=a[1][r++];
}
while(l<=a[0][0]) b[++b[0]]=a[0][l++];
while(r<=a[1][0]) b[++b[0]]=a[1][r++];
l=1;r=top[2];
while(l<=b[0]&&r<=a[2][0])
{
if(b[l]>a[2][r]) c[++c[0]]=b[l++];
else c[++c[0]]=a[2][r++];
}
while(l<=b[0]) c[++c[0]]=b[l++];
while(r<=a[2][0]) c[++c[0]]=a[2][r++];
for(int i=t;i<=n+m;i+=t) printf("%d ",c[i]+m*q);
printf("\n");
return 0;
}