• 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
    */
    
  • 相关阅读:
    谷歌Cartographer ROS初探
    在Ubuntu14.04_ROS_indigo上安装Kinect2驱动和bridge
    Turtlebot入门篇
    关于CV、SLAM、机器人导航的碎碎念
    C#与C++的区别!
    ++i 与 i++
    "+" 是怎样连接字符串的?
    不要重复你自己
    实习第四天
    微信小程序添加外部地图服务数据
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14648546.html
Copyright © 2020-2023  润新知