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
*/