建议数据加强,卡卡分块
查看原帖
建议数据加强,卡卡分块
389192
andychen_2012楼主2024/9/10 10:26

分块过了,甚至于是有问题的分块都能过。

我的做法是分三个块,第一个块是位置块,第二三个块是权值块。对三个块分别块内排序,位置块块内按照数的大小排序。我的错误是:对于询问 [l,r][l,r],若 [l,r][l,r] 在同一个位置块或者在相邻位置块,直接块内找到第 kk 小。而由于我仅进行了块内排序,所以不能对相邻位置块直接找块内第 kk 小。

代码见下,这是改完后的正确代码,原有的错误在第 99 行,注释掉了:

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
inline int read(){
	int x=0;
	int f=0,ch=0;
	while(ch<48||ch>57) f=(ch=='-'),ch=getchar();
	while(ch>47&&ch<58) x=(x<<3)+(x<<1)+(ch&15),ch=getchar();
	return f?-x:x;
}
inline void write(ll x,char end='\n'){
	if(x==0){
		putchar('0');
		putchar(end);
		return;
	}
	if(x<0) putchar('-'),x=-x;
	int ch[70]={0},cnt=0;
	while(x){
		ch[cnt++]=(int)(x%10);
		x/=10;
	}
	while(cnt--) putchar(ch[cnt]+48);
	putchar(end);
}
const int N=2e5+5;
const int S=450;
int n,m,s,B;
struct node{
	int x,id;
	friend bool operator<(node x,node y){
		return x.x<y.x;
	}
}d[N];
int a[N];
int st[S],ed[S];
int bel[N];
int start[S][S];
node block1[N],block2[N];
node block3[N];
//按大小排序,每个块内按原顺序排序 
inline bool cmp2(node x,node y){
	return x.id<y.id;
}
inline void initblock(){
	int T=sqrt(n);
	for(int i=1;i<=n;++i){
		bel[i]=(i-1)/T+1;
		if(!st[bel[i]])
			st[bel[i]]=i;
		ed[bel[i]]=i;
	}
	B=bel[n];
	for(int i=1;i<=n;++i)
		block1[i]=d[i];
	for(int i=1;i<=B;++i){
		sort(block1+st[i],block1+ed[i]+1);
	}
	sort(d+1,d+n+1);
	for(int i=1;i<=n;++i)
		block2[i]=block3[i]=d[i];
	for(int i=1;i<=B;++i){
		sort(block2+st[i],block2+ed[i]+1,cmp2);
	}
	for(int i=1;i<=B;++i){
		for(int j=st[i];j<=ed[i];++j){
			int to=bel[block2[j].id];
			if(!start[i][to]) start[i][to]=j;
		}
		start[i][B+1]=ed[i]+1;
		for(int j=B;j>=1;--j){
			if(!start[i][j]) start[i][j]=start[i][j+1];
		}
	}
}
inline void find(int x,int y,int l,int r,int k){
	for(int i=st[x];i<=ed[y];++i){
		if(block1[i].id>=l&&block1[i].id<=r) --k;
		if(k==0){
			write(block1[i].x);
			break;
		}
	}
}
inline void find2(int x,int y,int l,int r,int k){
	for(int i=st[x];i<=ed[y];++i){
		if(block3[i].id>=l&&block3[i].id<=r) --k;
		if(k==0){
			write(block3[i].x);
			break;
		}
	}
}
inline void solve(){
	int l=read(),r=read(),k=read();
	int x=bel[l],y=bel[r];
	if(x==y){//这里原来写的是x+1>=y,在这道题可以过,但是SPOJ的第一个点就挂了 
		find(x,y,l,r,k);
		return;
	}
	for(int i=1;i<=B;++i){
		int g=start[i][y]-start[i][x+1];
		for(int j=start[i][x+1]-1;j>=start[i][x];--j){
			if(block2[j].id>=l&&block2[j].id<=r) ++g;
		}
		for(int j=start[i][y];j<start[i][y+1];++j){
			if(block2[j].id>=l&&block2[j].id<=r) ++g;
		}
		if(g>=k){
			find2(i,i,l,r,k);
			break;
		}
		else k-=g;
	}
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;++i) a[i]=read(),d[i]={a[i],i};
	initblock();
	while(m--)
		solve();
	return 0;
}
2024/9/10 10:26
加载中...