HihoCoder

静态无修又是连续,模拟赛的时候很快就想到了莫队 + 回滚并查集

但是众所周知并查集并不支持删除操作,回滚并查集也只能按顺序删除

赛后得知有一个叫做回滚莫队的操作,即将左端点按照块排序,相同的块按照右端点从小到大排序

然后将所有左端点相同的块一起处理,因为右端点递增所以右端点很显然只有插入操作,

对于左端点来说,每次查询都回退到当前块的最右端,然后查询的时候向左插入,避开了原本的删除操作

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <bitset>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x)  
#define Pri(x) printf("%d
", x)
#define Prl(x) printf("%lld
",x)  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
const double PI = acos(-1.0);
const double eps = 1e-9;
const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,Q;
struct Edge{
    int to,next;
}edge[maxn * 2];
int head[maxn],tot,unit;
void init(){
    for(int i = 0 ; i <= N; i ++) head[i] = -1;
    tot = 0;
}
void add(int u,int v){
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
LL fac[maxn];
struct Query{
    int l,r;
    int id;
}query[maxn * 2];
int belong[maxn];
bool cmp(Query a,Query b){
    if(belong[a.l] == belong[b.l]) return a.r < b.r;
    return belong[a.l] < belong[b.l];
}
LL Sum,L,R;
int fa[maxn],size[maxn],sz[maxn];
int Stack[maxn],top;
void Init(){
    for(int i = 1; i <= N ; i ++){
        fa[i] = -1; size[i] = 0; sz[i] = 1;
    }
    top = 0;
}
int find(int x){
    while(fa[x] != -1) x = fa[x];
    return x;
}
bool Union(int x,int y){
    x = find(x); y = find(y);
    if(x == y) return false;
    if(size[x] > size[y]) swap(x,y);
    Stack[top++] = x;
    fa[x] = y;
    size[y] += size[x] + 1;
    Sum -= fac[sz[y]]; Sum -= fac[sz[x]];
    sz[y] += sz[x]; Sum += fac[sz[y]];
    return true;
}
void rewind(int t){
    while(top > t){
        int x = Stack[--top];
        size[fa[x]] -= size[x] + 1;
        sz[fa[x]] -= sz[x];
        fa[x] = -1;
    }
}
void add(int p){
    for(int i = head[p]; ~i ; i = edge[i].next){
        int v = edge[i].to;
        if(L <= v && v <= R) Union(v,p);
    }
}

int tree[maxn],Sz[maxn];
int Find(int x){
    if(x != tree[x]) return tree[x] = Find(tree[x]);
    return x;
}
LL cul(int l,int r){
    LL sum = 0;
    for(int i = l; i <= r; i ++){
        tree[i] = i; Sz[i] = 1;
    } 
    for(int i = l ; i <= r; i ++){
        for(int j = head[i]; ~j ; j = edge[j].next){
            int v = edge[j].to;
            if(l <= v && v <= r){
                int u = Find(i);
                v = Find(v);
                if(u != v){
                    tree[u] = v;
                    Sz[v] += Sz[u];
                }
            }
        }
    }
    for(int i = l; i <= r; i ++){
        int v = Find(i);
        if(i == v) sum += fac[Sz[i]];
    } 
    return sum;
}
LL ans[maxn];
void solve(){
    int up = N / unit;
    int j = 1; Init();
    for(int i = 0 ; i <= up; i ++){
        Sum = 0;
        L = (i + 1) * unit,R = L - 1;
        LL la,normal = L;
        for(;j <= Q && belong[query[j].l] == i; j ++){
            if(belong[query[j].r] == i){
                ans[query[j].id] = cul(query[j].l,query[j].r);
                continue;
            }
            while(R < query[j].r) add(++R);
            la = Sum; int tmp = top;
            while(L > query[j].l) add(--L);
            ans[query[j].id] = Sum;
            L = normal; rewind(tmp);
            Sum = la;
        }
        rewind(0);
        //cout << top << endl;
    }
}
int main(){
    int T; Sca(T);
    for(LL i = 0; i < maxn; i ++) fac[i] = i * (i - 1) / 2;
    while(T--){
        Sca3(N,M,Q); init(); unit = (int)sqrt(N);
        for(int i = 1; i <= M ; i ++){
            int u,v; Sca2(u,v);
            add(u,v); add(v,u);
        }
        for(int i = 1; i <= N ; i ++) belong[i] = i / unit;
        for(int i = 1; i <= Q; i ++){
            query[i].l = read();
            query[i].r = read();
            query[i].id = i;
        }
        sort(query + 1,query + 1 + Q,cmp);
        solve();
        for(int i = 1; i <= Q; i ++) Prl(ans[i]);
    } 
    return 0;
}
原文地址:https://www.cnblogs.com/Hugh-Locke/p/11385334.html