莫队算法较为朴素,适用于大部分的区间查询,主要在于对询问的排序
和区间的滑动
排序参照一下模板
struct node{
int l,r,id;
bool operator <(const node &_)const{
if(_.l/S!=l/S)return l<_.l;
return r<_.r;
}
}Q[M];
然后是L和R的滑动
int L=1,R=0;
FOR(i,1,m){
while(R.r)Add(++R);
while(L>Q[i].l)Add(--L);
while(R>Q[i].r)Del(R--);
while(L.l)Del(L++);
Ans[Q[i].id].x=ans;
Ans[Q[i].id].y=cal(Q[i].r-Q[i].l+1);
}
总复杂度约为 nn√
S= n2/3
复杂度 O(n5/3)
#include
using namespace std;
#define FOR(i,x,y) for(int i=(x),i##_END=(y);i<=i##_END;i++)
#define DOR(i,x,y) for(int i=(x),i##_END=(y);i>=i##_END;i--)
#define M 50005
int Sum[1000005],S,ans;
struct Query{
int l,r,t,id;
bool operator <(const Query &_)const {
if(l/S!=_.l/S)return l<_.l;
if(r/S!=_.r/S)return r<_.r;
return t<_.t;
}
}Q[M];
void Add(int a){
if(!Sum[a])ans++;
Sum[a]++;
}
void Del(int a){
Sum[a]--;
if(!Sum[a])ans--;
}
int Ans[M],Col[M],A[M],B[M],C[M],Pre[M];
int main(){
int n,m,cnt=0,t=0;
scanf("%d%d",&n,&m);
S=pow(n,0.67);
FOR(i,0,n-1)scanf("%d",&Col[i]),A[i]=Col[i];
FOR(i,1,m){
char str[5];
scanf("%s",str);
if(str[0]=='Q'){
cnt++;
scanf("%d %d",&Q[cnt].l,&Q[cnt].r);
Q[cnt].t=t,Q[cnt].id=cnt,Q[cnt].r--;
}
else {
t++;
int x,y;
scanf("%d%d",&x,&y);
Pre[t]=Col[x];
Col[x]=y;
B[t]=x;
C[t]=y;
}
}
FOR(i,0,n-1)Col[i]=A[i];
sort(Q+1,Q+1+cnt);
int L=0,R=-1,T=0;
FOR(i,1,cnt){
while(Tif(B[T]>=L&&B[T]<=R){
Del(Col[B[T]]);
Add(C[T]);
}
Col[B[T]]=C[T];
}
while(T>Q[i].t){
if(B[T]>=L&&B[T]<=R){
Del(Col[B[T]]);
Add(Pre[T]);
}
Col[B[T]]=Pre[T];
T--;
}
while(Rwhile(L>Q[i].l)L--,Add(Col[L]);
while(R>Q[i].r)Del(Col[R]),R--;
while(L1,cnt)printf("%d\n",Ans[i]);
return 0;
}
注意移动T时要判断区间
利用欧拉序,然后莫队更新
#include
using namespace std;
#define FOR(i,x,y) for(int i=(x),i##_END=(y);i<=i##_END;i++)
#define M 40005
#define N 100005
int Ans[N],S,ans;
bool mark[M];
//Link
int nxt[M<<1],To[M<<1],head[M],ttaE;
void addedge(int a,int b){nxt[++ttaE]=head[a];head[a]=ttaE;To[ttaE]=b;}
#define LFOR(i,x) for(int i=head[x];i;i=nxt[i])
//dfn
int tot,Lx[M<<1],Rx[M<<1],dfn[M<<1],son[M],fa[M],sz[M],dep[M];
void dfs(int x,int f){
son[x]=-1,sz[x]=1,fa[x]=f,dep[x]=dep[f]+1;
Lx[x]=++tot,dfn[tot]=x;
LFOR(i,x){
int y=To[i];
if(y==f)continue;
dfs(y,x);
sz[x]+=sz[y];
if(!~son[x]||sz[son[x]]int Top[M];
void ldfs(int x,int tp){
Top[x]=tp;
if(!~son[x])return;
ldfs(son[x],tp);
LFOR(i,x){
int y=To[i];
if(son[x]==y||fa[x]==y)continue;
ldfs(y,y);
}
}
int LCA(int x,int y){
while(Top[x]!=Top[y]){
if(dep[Top[x]]>dep[Top[y]])swap(x,y);
y=fa[Top[y]];
}
return dep[x]>dep[y]?y:x;
}
//Query
struct Query{
int l,r,lca,id;
Query(){lca=0;}
bool operator <(const Query &a)const{
if(l/S!=a.l/S)return lreturn r//Mo
int Sum[M],Val[M];
void Add(int x){
int a=dfn[x];
x=Val[a];
if(mark[a]){
Sum[x]--;
if(!Sum[x])ans--;
}
else {
Sum[x]++;
if(Sum[x]==1)ans++;
}
mark[a]^=1;
}
int B[M];
int main(){
int n,m;
cin>>n>>m;
FOR(i,1,n)scanf("%d",&Val[i]),B[i]=Val[i];
sort(B+1,B+n+1);
int len=unique(B+1,B+n+1)-B-1;
FOR(i,1,n)Val[i]=lower_bound(B+1,B+len+1,Val[i])-B;
FOR(i,1,n-1){
int x,y;
scanf("%d%d",&x,&y);
addedge(x,y);
addedge(y,x);
}
dfs(1,0);
ldfs(1,1);
S=sqrt(tot);
FOR(i,1,m){
int x,y;
scanf("%d%d",&x,&y);
if(Lx[x]>Lx[y])swap(x,y);
int lca=LCA(x,y);
if(x==lca)Q[i].l=Lx[x],Q[i].r=Lx[y];
else {Q[i].l=Rx[x],Q[i].r=Lx[y],Q[i].lca=Rx[lca];}
Q[i].id=i;
}
sort(Q+1,Q+m+1);
int L=1,R=0;
FOR(i,1,m){
while(Rwhile(L>Q[i].l)Add(--L);
while(R>Q[i].r)Add(R--);
while(Lif(Q[i].lca)Add(Q[i].lca);
Ans[Q[i].id]=ans;
if(Q[i].lca)Add(Q[i].lca);
}
FOR(i,1,m)printf("%d\n",Ans[i]);
return 0;
}