【GDOI2018模拟9.23】动态图

来源:互联网 发布:软件研发部门规划 编辑:程序博客网 时间:2024/05/22 07:07

Description:

这里写图片描述
1<=n<=10^6,1<=q<=200000

题解:

暴力可以用按秩合并并查集,这个数据结构支持删除。

对于正解,我们需要把l->r条边一次加进并查集,对于每一条边,它有贡献,就是加入它的时候,它会合并两个不同的集合。
反过来,它没有贡献,就是它所连着的两端本来就在一个集合里。

假设我们按1->r的顺序加入每一条边,当加入一条边时,设它是x,y,设z为x到y的路径上编号最小的边(x,y不在一个集合里是0)的编号,那么如果有询问包含这条边,且左端点小于等于z,那么当前这条边就是没有贡献的,否则它就是有贡献。

于是用lct维护一棵最大生成树,就可以求出z,再用主席树随便维护一下就行了。

Code:

#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define fo(i, x, y) for(int i = x; i <= y; i ++)#define min(a, b) ((a) < (b) ? (a) : (b))using namespace std;const int N = 1000000, M = 200005;int n, q, type, tt, u, v, l, r, ans, m;int t[N + M][2], fa[N + M], pf[N + M], rev[N + M], mi[N + M], dd[N + M];int g[N + M], tot;struct tree{    int l, r, s;}d[N * 10];struct edge {    int u, v, x, y, z;}e[N + M];int last[N + M];int lr(int x) {return t[fa[x]][1] == x;}void chan(int x) {if(x) swap(t[x][0], t[x][1]), rev[x] ^= 1;}void down(int x) {if(x && rev[x]) chan(t[x][0]), chan(t[x][1]), rev[x] = 0;}void update(int x) {    if(!x) return;    mi[x] = min(mi[t[x][0]], mi[t[x][1]]);    if(x > N) mi[x] = min(mi[x], x - N);}void xc(int x) {    for(; x; x = fa[x]) dd[++ dd[0]] = x;    for(; dd[0]; dd[0] --) down(dd[dd[0]]);}void rotate(int x) {    int y = fa[x], k = lr(x);    t[y][k] = t[x][!k]; if(t[x][!k]) fa[t[x][!k]] = y;    fa[x] = fa[y]; if(fa[y]) t[fa[y]][lr(y)] = x;        t[x][!k] = y; fa[y] = x; pf[x] = pf[y];    update(y); update(x);}void splay(int x, int y) {    xc(x);    while(fa[x] != y) {        if(fa[fa[x]] != y)            if(lr(x) == lr(fa[x])) rotate(fa[x]); else rotate(x);        rotate(x);    }}void dg(int x) {    if(x == 0) return;    down(x);    printf("%d %d %d %d tree\n", x, mi[x], t[x][0], t[x][1]);    dg(t[x][0]); dg(t[x][1]);}void access(int x) {    int y = 0;    while(x) {        splay(x, 0); fa[t[x][1]] = 0; pf[t[x][1]] = x;        t[x][1] = y; fa[y] = x; pf[y] = 0;        update(x); y = x; x = pf[x];    }    }void makeroot(int x) {    access(x); splay(x, 0); chan(x);}void link(int x, int y) {    makeroot(x); pf[x] = y; access(x);}void cut(int x, int y) {    makeroot(x); access(y); splay(y, 0);    t[y][0] = fa[x] = pf[x] = 0;    update(y);}int find_z(int x) {    down(x);    return t[x][0] == 0 ? x : find_z(t[x][0]);}int pd(int x, int y) {    makeroot(x); access(y); splay(y, 0);    return find_z(y) == x;}void change(int i, int x, int y, int l, int r) {    if(x == y) {        d[i].s += r;        return;    }    int m = (x + y) >> 1;    d[++ tot] = d[d[i].l], d[i].l = tot;    d[++ tot] = d[d[i].r], d[i].r = tot;    if(l <= m) change(d[i].l, x, m, l, r); else change(d[i].r, m + 1, y, l, r);    d[i].s = d[d[i].l].s + d[d[i].r].s;}int find(int i, int x, int y, int l, int r) {    if(i == 0) return 0;    if(x == l && y == r) return d[i].s;    int m = (x + y) >> 1;    if(r <= m) return find(d[i].l, x, m, l, r); else    if(l > m) return find(d[i].r, m + 1, y, l, r); else    return find(d[i].l, x, m, l, m) + find(d[i].r, m + 1, y, m + 1, r);}const int Mm = 200000;void xiu(int m, int last) {    g[m] = ++ tot; d[g[m]] = d[g[m - 1]];    change(g[m], 0, Mm, last, 1);}int qiu(int l, int r) {    return find(g[r], 0, Mm, 0, l - 1) - find(g[l - 1], 0, Mm, 0, l - 1);}int main() {    freopen("graph.in", "r", stdin);    freopen("graph.out", "w", stdout);    scanf("%d %d %d", &n, &q, &type);    fo(i, 0, N) mi[i] = 1e9;    g[0] = tot = 1;    fo(Q, 1, q) {        scanf("%d", &tt);        if(tt == 1) {            scanf("%d %d", &u, &v);            if(type) u = (u ^ ans) % n + 1;             if(type) v = (v ^ ans) % n + 1;            e[++ m].u = u, e[m].v = v;            if(u == v) {                last[m] = m; xiu(m, m);                continue;            }            if(pd(u, v)) {                makeroot(u); access(v); splay(v, 0);                int z = mi[v];                e[m].x = e[z].u; e[m].y = e[z].v; e[m].z = z;                cut(e[m].x, e[m].z + N); cut(e[m].y, e[m].z + N);                link(u, m + N); link(v, m + N);                last[m] = z; xiu(m, z);            } else {                link(u, m + N); link(v, m + N);                last[m] = 0; xiu(m, 0);            }        } else        if(tt == 2) {            if(e[m].u == e[m].v) {                m --; continue;            }            if(last[m]) {                cut(e[m].u, m + N); cut(e[m].v, m + N);                link(e[m].x, e[m].z + N); link(e[m].y, e[m].z + N);            } else {                cut(e[m].u, m + N); cut(e[m].v, m + N);            }            m --;        } else {            scanf("%d %d", &l, &r);            if(type) l = (l ^ ans) % m + 1;            if(type) r = (r ^ ans) % m + 1;            if(l > r) swap(l, r);            ans = n - qiu(l, r);            printf("%d\n", ans);        }    }}
原创粉丝点击