暴力在黑色卡常题中跑进最优解第一面
查看原帖
暴力在黑色卡常题中跑进最优解第一面
802681
wangziyue_AK楼主2024/12/20 08:20

这不是题解,不属于在讨论区中发题解。 这题以前时限1秒,绝大多数正常写法均无法通过,后来时限改为2秒,才能够让正常根号写法和原来想卡的根号写法一起通过。但暴力即可在1s内通过。即去掉占常数大头的块状链表,暴力在所属块内插入,没有分裂大块,然后就变成了简单好写的P2617 但这样复杂度显然错完了,因为可能会导致一个块特别大,插入和查询复杂度每次都到达线性。 AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define fi first
#define se second
typedef double db;
#define pb push_back
#define eb emplace_back
#define bcnt __builtin_popcount
#define TS printf("!!!tiaoshi\n")
const int inf=1e9+7;
const int N=1e5+5;
const int M=335;
int n,m,cnt,mx=70001,a[N],b[M],sz[M],bel[N],ax[M][M],ay[M][N],bx[M];
int k,sum,num[M][M*50];
inline void add(int x,int y,int k){
	for(;x<=cnt;x++) ax[x][bel[y]]+=k,ay[x][y]+=k;
}
void init(){
	k=sqrt(mx),sum=(mx-1)/k+1;
	for(int i=1;i<=mx;i++) bel[i]=(i-1)/k+1;
	k=sqrt(n);
	int la=1,nw=0;
	while(nw<n){
		nw=min(nw+k,n),cnt++;
		for(int i=la;i<=nw;i++) num[cnt][++sz[cnt]]=a[i];
		la=nw+1; 
	}
	for(int i=1;i<=cnt;i++){
		for(int j=1;j<=sz[i];j++) add(i,num[i][j],1);
	}k=sqrt(mx);
}
void out(){
	printf("init:%d %d %d\n",k,cnt,n);
	for(int i=1;i<=cnt;i++){
		printf("block:%d\n",i);
		for(int j=1;j<=sz[i];j++) printf("%d ",num[i][j]-1);puts("");
	}
}
inline pii find(int x){
	int bl=1,nw=0;
	while(nw+sz[bl]<x) nw+=sz[bl],bl++;
	return {bl,x-nw};
}
inline void get(int bl,int l,int r,int x){
	int y=(x-1)*k;
	for(int i=l;i<=r;i++){
		int z=num[bl][i],bz=bel[z];
		if(!x) bx[bz]++;
		else if(bz==x) bx[z-y]++;
	}
}
int qiu(int l,int r,int x){
	pii nl=find(l),nr=find(r);
	int bl=nl.fi,br=nr.fi,li=nl.se,ri=nr.se;
	if(bl==br) get(bl,li,ri,0);	
	else{
		get(bl,li,sz[bl],0),get(br,1,ri,0);
		for(int i=1;i<=sum;i++) bx[i]+=ax[br-1][i]-ax[bl][i];
	}
	int nw=1,tot=0,bj;
	while(tot+bx[nw]<x) tot+=bx[nw],nw++;
	x-=tot,bj=nw;
	int lim=(bj-1)*k;
	memset(bx,0,sizeof(bx));
	if(bl==br) get(bl,li,ri,bj);	
	else{
		get(bl,li,sz[bl],bj),get(br,1,ri,bj);
		for(int i=lim+1;i<=lim+k;i++) bx[i-lim]+=ay[br-1][i]-ay[bl][i];
	}
	nw=1;
	while(bx[nw]<x) x-=bx[nw],nw++;
	memset(bx,0,sizeof(bx));
	return nw+lim-1;  
}
inline void ins(int x,int y){
	if(x==n+1){
		add(cnt,y,1),n++;
		num[cnt][++sz[cnt]]=y;
		return;
	}
	pii nw=find(x);
	int bl=nw.fi,wz=nw.se;
	add(bl,y,1);
	for(int i=sz[bl];i>=wz;i--) num[bl][i+1]=num[bl][i];
	num[bl][wz]=y,sz[bl]++,n++;
}
inline void upd(int x,int y){
	pii nw=find(x);
	int bl=nw.fi,wz=nw.se;
	add(bl,num[bl][wz],-1),add(bl,y,1),num[bl][wz]=y;
}
int q;
#define gc getchar
inline int read(){
	int x=0;char ch=gc();
	while(ch<'0'||ch>'9') ch=gc();
	while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=gc();
	return x;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) a[i]=read()+1;
	init();
	scanf("%d",&q);
	char op[5];int l,r,x,lastans=0; 
	for(int i=1;i<=q;i++){
		scanf("%s",op+1);
		l=read(),r=read();
		l^=lastans,r^=lastans;
		if(op[1]=='Q'){
			scanf("%d",&x);x^=lastans;
			lastans=qiu(l,r,x);
			printf("%d\n",lastans);
		}else if(op[1]=='M') upd(l,r+1);
		else ins(l,r+1);
		//out();
	}
	return 0;
}
2024/12/20 08:20
加载中...