suxxsfe

一言(ヒトコト)

P4396 [AHOI2013]作业

P4396 [AHOI2013]作业

\([l,r]\) 区间里在 \([a,b]\) 中的数的个数很好求,但是数值个数不太好求
于是升一维,我们设 \(last_i=j\) 为第一个使得 \(a_j=a_i,j<i\)\(j\),没有就设为 \(0\)
然后求数值个数,就是求 \(l\le x_i\le r,a\le y_i\le b,0\le last_i\le l-1\)\(i\) 的个数
于是就是一个三维数点了
但这样每次 \(O(\log^3 n)\),完全不行,但发现没有修改,于是可以可持久化搞掉一维,也就是求数的个数(二维数点)用可持久化线段树,求数值个数用可持久化树套树
但又因为不强制在线,所以完全不用真的写一个可持久化树套树,可以离线下来用排序搞掉一维

主要就是这个升维(处理数值个数)和降维(可持久化)的思路

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<ctime>
#define reg register
#define EN puts("")
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
#define N 100006
int n;
struct data{
	int k,a,b,p,o,id;
}q[2*N];
int tot;
inline int cmp(const data &a,const data &b){return a.k<b.k;}
struct BIT1{
	#define lowbit(x) (x&(-x))
	int tree[N];
	inline int ask(reg int pos){
		reg int ans=0;
		for(;pos;pos-=lowbit(pos)) ans+=tree[pos];
		return ans;
	}
	inline void add(reg int pos){
		for(;pos<=100000;pos+=lowbit(pos)) tree[pos]++;
	}
	#undef lowbit
}Q1;
struct Segment{
	struct Node{
		int ls,rs;
		int cnt;
	}p[N*207];
	int root[N],null;
	int tot;
	inline void New(int &a){a=++tot;p[a].ls=p[a].rs=null;p[a].cnt=0;}
	inline void init(){New(null);for(reg int i=1;i<=100001;i++) New(root[i]);}
	void add(int &o,int l,int r,int pos){
		if(o==null) New(o);
		p[o].cnt++;
		if(l==r) return;
		int mid=(l+r)>>1;
		pos<=mid?add(p[o].ls,l,mid,pos):add(p[o].rs,mid+1,r,pos);
	}
	int ask(int o,int l,int r,int ql,int qr){
		if(o==null) return 0;
		if(ql<=l&&r<=qr) return p[o].cnt;
		int mid=(l+r)>>1,ans=0;
		if(ql<=mid) ans+=ask(p[o].ls,l,mid,ql,qr);
		if(qr>mid) ans+=ask(p[o].rs,mid+1,r,ql,qr);
		return ans;
	}
}S;
struct BIT2{
	#define lowbit(x) (x&(-x))
	inline int ask(reg int pos,int valL,int valR){
		reg int ans=0;pos++;
		for(;pos;pos-=lowbit(pos)) ans+=S.ask(S.root[pos],1,n,valL,valR);
		return ans;
	}
	inline void add(reg int pos,int val){
		pos++;
		for(;pos<=100001;pos+=lowbit(pos)) S.add(S.root[pos],1,n,val);
//		puts("-----------------------------------------");
	}
	#undef lowbit
}Q2;
int ans1[N],ans2[N];
int a[N],last[N],tmp[N];
inline void work(){
	int pos=1;
	for(reg int i=1;i<=tot;i++){
		while(pos<=q[i].k) Q1.add(a[pos]),Q2.add(last[pos],a[pos]),pos++;
		ans1[q[i].id]+=q[i].o*(Q1.ask(q[i].b)-Q1.ask(q[i].a-1));
		ans2[q[i].id]+=q[i].o*Q2.ask(q[i].p,q[i].a,q[i].b);
	}
}
int main(){
//		printf("%lld\n",sizeof Q1+sizeof Q2+sizeof S);
	n=read();int m=read();
	S.init();
	for(reg int i=1;i<=n;i++){
		a[i]=read();
		last[i]=tmp[a[i]];tmp[a[i]]=i;
	}
	for(reg int i=1;i<=m;i++){
		int l=read(),r=read(),a=read(),b=read();
		q[++tot].k=l-1;q[tot].a=a;q[tot].b=b;q[tot].o=-1;q[tot].id=i;q[tot].p=l-1;
		q[++tot].k=r;q[tot].a=a;q[tot].b=b;q[tot].o=1;q[tot].id=i;q[tot].p=l-1;
	}
	std::sort(q+1,q+1+tot,cmp);
	work();
	for(reg int i=1;i<=m;i++) printf("%d %d\n",ans1[i],ans2[i]);
	return 0;
}
posted @ 2021-03-18 21:11  suxxsfe  阅读(58)  评论(0编辑  收藏  举报