zoukankan      html  css  js  c++  java
  • 洛谷 P4396 [AHOI2013]作业 莫队+值域分块

    题目描述

    题目传送门

    分析

    因为询问是关于区间的,并且没有强制在线,所以能用莫队解决

    但是还要支持查询区间内大于等于 (a),小于等于 (b) 的数的个数和数值的个数

    所以还要套一个数据结构

    比较好想的做法是对权值开一个数状数组

    (logn) 修改,(logn) 查询

    复杂度有点高

    考虑莫队的本质是进行了 (nsqrt{m}) 次修改和 (m) 次查询

    我们的修改必须是 (O(1)) 的,但是查询的次数比较少,可以 (O(sqrt{n})) 解决

    所以可以用值域分块代替树状数组,可以做到 (O(nsqrt{m}+msqrt{n})) 的复杂度

    代码

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #define rg register
    inline int read(){
    	rg int x=0,fh=1;
    	rg char ch=getchar();
    	while(ch<'0' || ch>'9'){
    		if(ch=='-') fh=-1;
    		ch=getchar();
    	}
    	while(ch>='0' && ch<='9'){
    		x=(x<<1)+(x<<3)+(ch^48);
    		ch=getchar();
    	}
    	return x*fh;
    }
    const int maxn=1e6+5;
    int n,m,a[maxn],blo,ans1[maxn],ans2[maxn],nans1,nans2,mmax,shuyu[maxn],cntcol[maxn],cntnum[maxn],cnt[maxn],lmax[maxn],rmax[maxn];
    struct jie{
    	int l,r,jla,jlb,id;
    	jie(){}
    	jie(rg int aa,rg int bb,rg int cc,rg int dd,rg int ee){
    		l=aa,r=bb,jla=cc,jlb=dd,id=ee;
    	}
    }b[maxn];
    bool cmp(rg jie aa,rg jie bb){
    	if(shuyu[aa.l]==shuyu[bb.l]){
    		return shuyu[aa.l]&1?aa.r<bb.r:aa.r>bb.r;
    	} else {
    		return aa.l<bb.l;
    	}
    }
    void xg(rg int val,rg int op){
    	if(cnt[val]==0) cntcol[shuyu[val]]++;
    	cnt[val]+=op;
    	cntnum[shuyu[val]]+=op;
    	if(cnt[val]==0) cntcol[shuyu[val]]--;
    }
    void cx(rg int nl,rg int nr){
    	nans1=0,nans2=0;
    	for(rg int i=nl;i<=std::min(nr,rmax[shuyu[nl]]);i++){
    		nans1+=cnt[i];
    		nans2+=(cnt[i]!=0);
    	}
    	if(shuyu[nl]==shuyu[nr]) return;
    	for(rg int i=nr;i>=lmax[shuyu[nr]];i--){
    		nans1+=cnt[i];
    		nans2+=(cnt[i]!=0);
    	}
    	for(rg int i=shuyu[nl]+1;i<=shuyu[nr]-1;i++){
    		nans1+=cntnum[i];
    		nans2+=cntcol[i];
    	}
    }
    int main(){
    	memset(lmax,0x3f,sizeof(lmax));
    	n=read(),m=read();
    	for(rg int i=1;i<=n;i++) a[i]=read();
    	mmax=n;
    	rg int aa,bb,cc,dd;
    	for(rg int i=1;i<=m;i++){
    		aa=read(),bb=read(),cc=read(),dd=read();
    		mmax=std::max(mmax,bb);
    		b[i]=jie(aa,bb,cc,dd,i);
    	}
    	blo=sqrt(mmax);
    	for(rg int i=1;i<=mmax;i++){
    		shuyu[i]=(i-1)/blo+1;
    		lmax[shuyu[i]]=std::min(lmax[shuyu[i]],i);
    		rmax[shuyu[i]]=std::max(rmax[shuyu[i]],i);
    	}
    	std::sort(b+1,b+1+m,cmp);
    	rg int nl=1,nr=0;
    	for(rg int i=1;i<=m;i++){
    		while(nr<b[i].r) xg(a[++nr],1);
    		while(nl>b[i].l) xg(a[--nl],1);
    		while(nr>b[i].r) xg(a[nr--],-1);
    		while(nl<b[i].l) xg(a[nl++],-1);
    		cx(b[i].jla,b[i].jlb);
    		ans1[b[i].id]=nans1;
    		ans2[b[i].id]=nans2;
    	}
    	for(rg int i=1;i<=m;i++) printf("%d %d
    ",ans1[i],ans2[i]);
    	return 0;
    }
    
  • 相关阅读:
    ajax跨域
    抽奖概率计算
    应用版本
    empty
    java线程池原理
    java队列
    jquery选择器项目实例分析
    jquery操作dom
    40款非常棒的 jQuery 插件和制作教程(系列一)
    vijosP1046 观光旅游(最小环)
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/14266201.html
Copyright © 2011-2022 走看看