1. 程式人生 > 其它 >luogu P5356 [Ynoi2017] 由乃打撲克

luogu P5356 [Ynoi2017] 由乃打撲克

題面傳送門
真 塊長的藝術。
這種東西顯然樹型別維護不了,我們考慮分塊。
根據套路我們維護每個塊的有序數列記為\(B\),然後每次修改歸併,每次查詢先二分然後零散塊暴力查整塊二分即可。
設塊長為\(S\),修改複雜度\(O(S+\frac{n}{S})\),查詢複雜度\(O(logn(S+\frac{n}{S}logS))\)
我們發現零散塊很浪費,我們把兩個零散塊提前歸併然後單獨二分即可,就可以把S提到外面。
然後均值不等式一下就是\(S=\sqrt nlogn\)最優複雜度\(O(n\sqrt nlogn)\)
然後你發現這個東西過不去因為歸併常數實在是太大了。
所以我們適當降低塊長,我除了\(\sqrt 5\)


然後二分邊界也是可以直接查出來。
這樣每個點大概就是1.3s的了。
其實塊內二分邊界還可以利用上一次調,但是我很懶就沒有寫了反正能過。
code:

#include <vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<set>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 100000
#define M 350
#define eps (1e-5)
#define mod (1<<31)
#define U unsigned int
using namespace std;
int n,m,K,nx,ny,x,y,z,op,G[M+5],A[N+5],B[N+5],C[N+5],Ch,D[N+5],Dh,F[N+5],H,fr[M+5],en[M+5],Ans;ll l,r,mid;
I bool cmp(int x,int y){return A[x]<A[y];}
I int check(ll mid){
	re int i,l,r,mi,Ans=0;l=0;r=H+1;while(l+1<r) mi=l+r>>1,(G[F[mi]/K]+A[F[mi]]<=mid?l:r)=mi;Ans+=l;
	for(i=nx+1;i<ny;i++){
		l=fr[i]-1;r=en[i]+1;while(l+1<r) mi=l+r>>1,(G[i]+A[B[mi]]<=mid?l:r)=mi;Ans+=l-fr[i]+1;
	}
	return Ans;
}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	re int i,j,h;scanf("%d%d",&n,&m);K=max(sqrt(n/5)*log2(n),1);for(i=1;i<=n;i++) scanf("%d",&A[i]),B[i]=i;
	for(i=0;i<=n/K;i++) fr[i]=max(i*K,1),en[i]=min(n,i*K+K-1);
	for(i=0;i<=n/K;i++) sort(B+fr[i],B+en[i]+1,cmp); 
	while(m--){
		scanf("%d%d%d%d",&op,&x,&y,&z);nx=x/K;ny=y/K;if(op==2){
			if(nx==ny){
				for(i=x;i<=y;i++) A[i]+=z;Ch=Dh=0;for(i=fr[nx];i<=en[nx];i++)(B[i]>=x&&B[i]<=y?C[++Ch]:D[++Dh])=B[i];H=fr[nx];  
				j=h=1;while(j<=Ch||h<=Dh)B[H++]=(j<=Ch&&(h>Dh||A[C[j]]<A[D[h]]))?C[j++]:D[h++];continue;
			}
			for(i=nx+1;i<ny;i++) G[i]+=z;for(i=x;i<=en[nx];i++) A[i]+=z;for(i=fr[ny];i<=y;i++) A[i]+=z;
			Ch=Dh=0;for(i=fr[nx];i<=en[nx];i++)(B[i]>=x?C[++Ch]:D[++Dh])=B[i];H=fr[nx];  
			j=h=1;while(j<=Ch||h<=Dh)B[H++]=(j<=Ch&&(h>Dh||A[C[j]]<A[D[h]]))?C[j++]:D[h++];
			Ch=Dh=0;for(i=fr[ny];i<=en[ny];i++)(B[i]<=y?C[++Ch]:D[++Dh])=B[i];H=fr[ny];  
			j=h=1;while(j<=Ch||h<=Dh)B[H++]=(j<=Ch&&(h>Dh||A[C[j]]<A[D[h]]))?C[j++]:D[h++];
		}
		else{
			if(y-x+1<z){printf("-1\n");continue;}
			if(nx==ny){
				for(i=fr[nx];i<=en[ny];i++) {z-=(B[i]>=x&&B[i]<=y);if(!z) {printf("%d\n",A[B[i]]+G[nx]);break;}}continue; 
			}
			Ch=Dh=H=0;for(i=fr[nx];i<=en[nx];i++) B[i]>=x&&(C[++Ch]=B[i]);for(i=fr[ny];i<=en[ny];i++) B[i]<=y&&(D[++Dh]=B[i]);
			j=h=1;while(j<=Ch||h<=Dh)F[++H]=(j<=Ch&&(h>Dh||A[C[j]]+G[nx]<A[D[h]]+G[ny]))?C[j++]:D[h++];
			l=A[F[1]]+G[F[1]/K];r=A[F[H]]+G[F[H]/K];for(i=nx+1;i<ny;i++) l=min(l,A[B[fr[i]]]+G[i]),r=max(r,A[B[en[i]]]+G[i]);l--;r++;
			while(l+1<r)mid=l+r>>1,(check(mid)<z?l:r)=mid;printf("%lld\n",r);
		}
	}
}