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;
}