莫队算法
1.普通莫队
一般只要修改update
带修改莫队就是维护一个时间戳,记录当前的版本和之前的版本
树上莫队,就是将树变成链的结构,在欧拉序上进行莫队,其中求lca我是用的倍增的方法当然可以用树链剖分还有一些高级方法。
在这里插入代码片
#include<iostream>
#include<math.h>
#include<algorithm>
using namespace std;
const int maxn = 1e6+5;
int a[maxn],B,n,m,pos[maxn];
int ANS[maxn],ans = 0,cnt[maxn];
inline void update(int id,int sign){
int x = a[id];
cnt[x] += sign;
if(sign == 1 && cnt[x] == 1) ans++;
if(sign == -1 && cnt[x] == 0) ans--;
}
struct Rec{
int l,r,id;
bool operator < (const Rec& p1) const{
if( pos[l] != pos[p1.l] ) return r < p1.r;
return pos[l] < pos[p1.l];
}
}q[maxn];
int main(){
cin >> n;
B = sqrt(n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
pos[i] = i/B;
}
cin >> m;
for(int i=0;i<m;i++){
int l,r;
scanf("%d %d",&l,&r);
q[i].l = l;
q[i].r = r;
q[i].id = i;
}
sort(q,q+m);
int l = 1, r = 0;
for(int i=0;i<m;i++){
while(l < q[i].l) update(l++,-1);
while(l > q[i].l) update(--l,1);
while(r > q[i].r) update(r--,-1);
while(r < q[i].r) update(++r,1);
ANS[q[i].id] = ans;
}
for(int i=0;i<m;i++){
printf("%d\n",ANS[i]);
}
}
#include<iostream>
using namespace std;
#include<math.h>
#include<algorithm>
const int maxn = 1e5+5;
int ans = 0,ANS[maxn];
int B,a[maxn],pos[maxn];
int n,m;
struct Rec{
int id,l,r;
bool operator <(const Rec& q)const {
if(pos[q.l] == pos[l]) return r < q.r;
return pos[l] < pos[q.l];
}
};
Rec q[maxn];
void update(int id,int sign){
int x = a[id];
ans += sign * x;
}
int main(){
scanf("%d %d",&n,&m);
B = sqrt(n);
for(int i=1;i<=n;i++){
pos[i] = i/B;
}
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++){
int l,r;
scanf("%d %d",&l,&r);
q[i].id = i,q[i].l = l,q[i].r = r;
}
int l = 1,r = 0;
sort(q+1,q+1+m);
for(int i=1;i<=m;i++){
while(l < q[i].l) update(l++,-1);
while(l > q[i].l) update(--l,1);
while(r > q[i].r) update(r--,-1);
while(r < q[i].r) update(++r,1);
ANS[q[i].id] = ans;
}
for(int i=1;i<=m;i++){
printf("%d\n",ANS[i]);
}
}
//2.带修改的莫队
#include<iostream>
using namespace std;
#include<math.h>
#include<algorithm>
const int maxn = 1e6+5;
int B,a[maxn],pos[maxn];
int n,m;
struct Rec{
int id,l,r,tim;
bool operator<(Rec& q){
return pos[l] == pos[q.l] ? (pos[r] == pos[q.r]?
tim < q.tim :pos[r] < pos[q.r]):pos[l] < pos[q.l];
}
};
Rec q[maxn];int len = 0;
int cnt[maxn];
struct chage{
int x,old,now;
};
chage chan[maxn];int clen = 0;
int ANS[maxn],ans =0 ;
void update(int x,int sign){
ans += sign * x;
}
int main(){
scanf("%d %d",&n,&m);
B = pow(n,2/3);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){
pos[i] = i / B;
}
for(int i=1;i<=m;i++){
char s[10];
int x,y;
scanf("%s",s); scanf("%d %d",&x,&y);
if(s[0] == 'R'){
chan[++clen].x = x;
chan[clen].old = a[x];
chan[clen].now = a[x] = y;
}
else{
q[++len].id = len;
q[len].l = x;
q[len].r = y;
q[len].tim = clen;
}
}
sort(q+1,q+1+len);
int l = 1,r = 0,tim = clen;
for(int i=1;i<=m;i++){
while(tim > q[i].tim){
int x = chan[tim].x;
if( l <= x && x <= r) update(a[x],-1),update(chan[tim].old,1);
a[x] = chan[tim].old;
--tim;
}
while(tim < q[i].tim){
tim++;
int x = chan[tim].x;
if(l <= x && x <= r){
update(a[x],-1);
update(chan[tim].now,1);
}
a[x] = chan[tim].now;
}
while(q[i].l < l) update(a[--l],1);
while(q[i].l > l) update(a[l++],-1);
while(q[i].r < r) update(a[r--],-1);
while(q[i].r > r) update(a[++r],1);
ANS[q[i].id] = ans;
}
for(int i=1;i<=len;i++){
printf("%d\n",ANS[i]);
}
}
//3.树上莫队
#include<iostream>
using namespace std;
#include<algorithm>
#include<math.h>
#include<vector>
const int maxn = 5e6+5;
vector<int> v;
int head[maxn],tot = 0;
struct Edge{
int to,next;
}edge[maxn];
void add(int u,int v){
edge[++tot].to = v;
edge[tot].next = head[u];
head[u] = tot;
}
int pos[maxn],B;
struct Rec{
int id,l,r,p;
bool operator <(const Rec& q1)const{
if(pos[l] == pos[q1.l]) return r < q1.r;
return pos[l] < pos[q1.l];
}
}q[maxn];
int first[maxn],last[maxn],seq[maxn],top;
int w[maxn];
int f[maxn][22],dep[maxn];
int ans[maxn],res = 0,vis[maxn],cnt[maxn];
void dfs1(int u,int fa){
seq[++top] = u;
first[u] = top;
for(int i=head[u];i;i=edge[i].next){
int v = edge[i].to;
if(v == fa) continue;
dfs1(v,u);
}
seq[++top] = u;
last[u] = top;
}
void dfs2(int u,int f1){
f[u][0] = f1;
for(int i=1;i<=20;i++){
f[u][i] = f[f[u][i-1]][i-1];
}
for(int i=head[u];i;i=edge[i].next){
int v = edge[i].to;
if(f1 == v) continue;
dep[v] = dep[u] + 1;
dfs2(v,u);
}
}
int lca(int u,int v){
if(dep[u] < dep[v]) swap(u,v);
for(int i=20;i>=0;i--){
if(dep[f[u][i]] >= dep[v]){
u = f[u][i];
}
}
if(u == v){
return u;
}
for(int i=20;i>=0;i--){
if(f[u][i] != f[v][i]){
u = f[u][i];
v = f[v][i];
}
}
return f[u][0];
}
void update(int x,int& res){
vis[x] ^= 1;
if(vis[x] == 0){
cnt[w[x]] -- ;
if(cnt[w[x]] == 0) res--;
}
else{
cnt[w[x]] ++;
if(cnt[w[x]] == 1) res++;
}
}
int main(){
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
v.push_back(w[i]);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;i++){
w[i] = lower_bound(v.begin(),v.end(),w[i]) - v.begin();
}
for(int i=1;i<=n-1;i++){
int u,v;
scanf("%d %d",&u,&v);
add(u,v);
add(v,u);
}
dep[1] = 1;
dfs1(1,-1);
dfs2(1,-1);
for(int i=0;i<m;i++){
int u,v;
scanf("%d %d",&u,&v);
if(first[u] > first[v]){
swap(u,v);
}
int p = lca(u,v);
if(u == p){
q[i] = {i,first[u],first[v],0};
}
else{
q[i] = {i,last[u],first[v],p};
}
}
B = sqrt(top);
for(int i=1;i<=top;i++){
pos[i] = i / B;
}
sort(q,q+m);
for(int i = 0,l = 1,r = 0,res = 0;i<m;i++){
while(l < q[i].l) update(seq[l++],res);
while(l > q[i].l) update(seq[--l],res);
while(r > q[i].r) update(seq[r--],res);
while(r < q[i].r) update(seq[++r],res);
if(q[i].p){
update(q[i].p,res);
}
ans[q[i].id] = res;
if(q[i].p){
update(q[i].p,res);
}
}
for(int i=0;i<m;i++){
printf("%d\n",ans[i]);
}
}