P4396 [AHOI2013]作业

P4396 [AHOI2013]作业

P4396 [AHOI2013]作业

CDQ分治+树状数组或者莫队+树状数组。

CDQ分治做法:

第一问很简单,就是区间询问大于等于一个数且小于等于一个数的个数,容易发现这就是二维偏序。

然后发现第二问就是矩阵数颜色,那么我们沿用 HH的项链 这道题的经典思路,对每个颜色维护一个 (pre) ,把区间数颜色转化为二维偏序,这里就是三维偏序了。

注意:这里必须按第一关键字排序过后使用 (id) 来进行排序,修改在前询问在后!!

不知道为什么 sort 版本比归并版本慢了这么多..

代码(sort):

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
const int N=1e6+5,M=1e5+2;
int n,m;
int c[N],a[N],pre[N],pos[N],Ans[N],Ans1[N],Cnt;
void Add(int x,int v){x++;for(;x<=M;x+=(x&(-x))) c[x]+=v;return ;}
int Ask(int x){x++;int res=0;for(;x;x-=(x&(-x))) res+=c[x];return res;}
void Clear(int x){x++;for(;x<=M;x+=(x&(-x))) c[x]=0;return ;}
struct node{int d1,d2,d3,id,tag;}Q[N];
inline bool CmpD1(node x,node y){
	if(x.d1!=y.d1) return x.d1<y.d1;
	return x.id<y.id;
}
inline bool CmpD2(node x,node y){
	if(x.d2!=y.d2) return x.d2<y.d2;
	return x.id<y.id;
}
void CDQ_Divide(int l,int r){
	if(l==r) return ;
	int mid=l+r>>1,tot=l;
	CDQ_Divide(l,mid),CDQ_Divide(mid+1,r);
	sort(Q+l,Q+mid+1,CmpD2),sort(Q+mid+1,Q+r+1,CmpD2);
	for(int i=mid+1,j=l,Q1=0;i<=r;i++){
		while(Q[j].d2<=Q[i].d2&&j<=mid){
			if(!Q[j].id) Add(Q[j].d3,1),Q1++;
			j++;tot++;
		}
		if(Q[i].id) Ans[Q[i].id]+=Ask(Q[i].d3)*Q[i].tag,Ans1[Q[i].id]+=Q1*Q[i].tag;
	}
	for(int i=l;i<tot;i++) if(!Q[i].id) Add(Q[i].d3,-1);
	return ;
}
int main(){
	read(n),read(m);
	for(int i=1;i<=n;i++){
		read(a[i]);
		pre[i]=pos[a[i]];
		pos[a[i]]=i;
		Q[++Cnt]=(node){i,a[i],pre[i],0,0};
	}
	for(int i=1;i<=m;i++){
		int l,r,a,b;read(l),read(r),read(a),read(b);
		Q[++Cnt]=(node){l-1,a-1,l-1,i,1};
		Q[++Cnt]=(node){r,b,l-1,i,1};
		Q[++Cnt]=(node){l-1,b,l-1,i,-1};
		Q[++Cnt]=(node){r,a-1,l-1,i,-1};
	}
	sort(Q+1,Q+Cnt+1,CmpD1);
	CDQ_Divide(1,Cnt);
	for(int i=1;i<=m;i++) write(Ans1[i]),putchar(' '),write(Ans[i]),putchar('
');
	return 0;
}
/*
5 3
1 5 4 2 2 
5 5 2 2
4 4 2 2
4 5 2 2
*/

代码(归并):

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
const int N=1e6+5,M=1e5+2;
int n,m;
int c[N],a[N],pre[N],pos[N],Ans[N],Ans1[N],Cnt;
void Add(int x,int v){x++;for(;x<=M;x+=(x&(-x))) c[x]+=v;return ;}
int Ask(int x){x++;int res=0;for(;x;x-=(x&(-x))) res+=c[x];return res;}
void Clear(int x){x++;for(;x<=M;x+=(x&(-x))) c[x]=0;return ;}
struct node{int d1,d2,d3,id,tag;}Q[N],tmp[N];
inline bool CmpD1(node x,node y){
	if(x.d1!=y.d1) return x.d1<y.d1;
	return x.id<y.id;
}
inline bool CmpD2(node x,node y){
	if(x.d2!=y.d2) return x.d2<y.d2;
	return x.id<y.id;
}
void CDQ_Divide(int l,int r){
	if(l==r) return ;
	int mid=l+r>>1,tot=l;
	CDQ_Divide(l,mid),CDQ_Divide(mid+1,r);
	int i=l,j=mid+1,pos=l,Q1=0;
	while(i<=mid&&j<=r){
		if(Q[j].d2>=Q[i].d2){
			if(Q[i].id==0) Add(Q[i].d3,1),Q1++;
			tmp[pos++]=Q[i++];
		}
		else{
			if(Q[j].id){
				Ans1[Q[j].id]+=Q[j].tag*Q1;
				Ans[Q[j].id]+=Q[j].tag*Ask(Q[j].d3);
			}
			tmp[pos++]=Q[j++];
		}
	}
	while(i<=mid){
		if(Q[i].id==0) Add(Q[i].d3,1),Q1++;
		tmp[pos++]=Q[i++];
	}
	while(j<=r){
		if(Q[j].id){
			Ans1[Q[j].id]+=Q[j].tag*Q1;
			Ans[Q[j].id]+=Q[j].tag*Ask(Q[j].d3);
		}
		tmp[pos++]=Q[j++];
	}
	for(int t=l;t<=mid;t++) if(Q[t].id==0) Add(Q[t].d3,-1);
	for(int t=l;t<=r;t++) Q[t]=tmp[t];
	return ;
}
int main(){
	read(n),read(m);
	for(int i=1;i<=n;i++){
		read(a[i]);
		pre[i]=pos[a[i]];
		pos[a[i]]=i;
		Q[++Cnt]=(node){i,a[i],pre[i],0,0};
	}
	for(int i=1;i<=m;i++){
		int l,r,a,b;read(l),read(r),read(a),read(b);
		Q[++Cnt]=(node){l-1,a-1,l-1,i,1};
		Q[++Cnt]=(node){r,b,l-1,i,1};
		Q[++Cnt]=(node){l-1,b,l-1,i,-1};
		Q[++Cnt]=(node){r,a-1,l-1,i,-1};
	}
	sort(Q+1,Q+Cnt+1,CmpD1);
	CDQ_Divide(1,Cnt);
	for(int i=1;i<=m;i++) write(Ans1[i]),putchar(' '),write(Ans[i]),putchar('
');
	return 0;
}
/*
5 3
1 5 4 2 2 
5 5 2 2
4 4 2 2
4 5 2 2
*/
原文地址:https://www.cnblogs.com/Akmaey/p/14648546.html