把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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);
		}
	}
}
posted @ 2021-06-16 20:40  275307894a  阅读(51)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end