讲解:https://www.cnblogs.com/WAMonster/p/10118934.html
1.莫队
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 1010000
#define maxb 1010
using namespace std;
int aa[maxn],cnt[maxn],belong[maxn];
int n,m,size,bnum,now,ans[maxn];
struct query{
int l,r,id;
}q[maxn];
int cmp(query a,query b)
{
return (belong[a.l]^belong[b.l])?belong[a.l]<belong[b.l]:(belong[a.l]&1)?a.r<b.r:a.r>b.r;
}
void add(int pos)
{
if(!cnt[aa[pos]]) ++now;
++cnt[aa[pos]];
}
void del(int pos)
{
--cnt[aa[pos]];
if(!cnt[aa[pos]]) --now;
}
int main()
{
scanf("%d",&n);
size=sqrt(n);
bnum=n/size;if(n%size) bnum++;
for(int i=1;i<=n;i++)
{
belong[i]=(i-1)/size+1;
}
for(int i=1;i<=n;i++) scanf("%d",&aa[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
int l=1,r=0;
for(int i=1;i<=m;i++)
{
int ql=q[i].l,qr=q[i].r;
while(l<ql) del(l++);
while(l>ql) add(--l);
while(r<qr) add(++r);
while(r>qr) del(r--);
ans[q[i].id]=now;
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
2.主席树
思路:root[i]维护的是数组[1,i]中每个数的最后位置
这样查询 [ l , r ] 内的答案就是查询第 r 个版本的主席树中 [ l , r ] 的 sum
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N=2e5+10;
#define ll long long
int n,m,x,p;
struct tree{
int l,r;int cnt;
}t[N*4+N*17];
int root[N],idx;
int build(int l,int r)
{
int q=++idx;
t[q].cnt=0;
if(l==r) return l;
int mid=(l+r)/2;
t[q].l=build(l,mid);
t[q].r=build(mid+1,r);
return q;
}
int insert(int p,int l,int r,int x,int k)
{
int q=++idx;
t[q]=t[p];
if(l==r)
{
t[q].cnt+=k;
return q;
}
int mid=(l+r)/2;
if(x<=mid)
{
t[q].l=insert(t[p].l,l,mid,x,k);
}
else t[q].r=insert(t[p].r,mid+1,r,x,k);
t[q].cnt=t[t[q].l].cnt+t[t[q].r].cnt;
return q;
}
int query(int p,int l,int r,int L,int R)
{
if(l>=L&&r<=R) return t[p].cnt;
int mid=(l+r)/2;
int ans=0;
if(L<=mid)
{
ans=ans+query(t[p].l,l,mid,L,R);
}
if(R>mid)
ans=ans+query(t[p].r,mid+1,r,L,R);
return ans;
}
int last[1000010];
int main()
{
scanf("%d",&n);
root[0]=build(1,n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(last[x]==0)
{
root[i]=insert(root[i-1],1,n,i,1);
}
else
{
root[i]=insert(root[i-1],1,n,last[x],-1);
root[i]=insert(root[i],1,n,i,1);
}
last[x]=i;
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(root[r],1,n,l,r));
}
}

本文详细介绍了莫队算法和主席树的实现原理及应用。莫队算法通过预处理和分块技术优化区间查询问题,主席树则利用线段树变种高效处理区间更新与查询。代码示例清晰展示了两种算法的结构与操作流程。

303

被折叠的 条评论
为什么被折叠?



