loj #121. 「离线可过」动态图连通性

嘟嘟嘟


我用的方法是线段树+并差集,简单易懂,常数略大。


我们按操作时间建立线段树,并且每一个节点开一个vector,记录这个区间内有哪些边。然后算出每一条边的出现时间(这个时间必须是一段连续的区间,如果他加入后删除又加入,那就算两条边),像区间更新打标记一样把这条边放进对应节点的vector。


对于询问,我们只用在这个时间点对应的节点上标记一下即可。显然每一个叶子结点最多只能有一个询问。


接下来,我们dfs整棵线段树,走到一个节点,就把这个节点的vector里面的所有边加进并差集中。到了叶子结点的时候,如果有询问,就并差集查一下连通性即可。然后回溯的时候,我们要撤销所有的合并操作,即维护一个可撤销的并差集(撤销最后一条加进来的边)。这个也不难,我们每一次按秩合并的时候用启发式合并,并且不要路径压缩,然后撤销的时候恢复两个集合原来的代表元和大小即可。
写起来很简单:

int p[maxn], siz[maxn], top = 0;
pr st[maxm << 2];
In int Find(int x) {return x == p[x] ? x : Find(p[x]);}
In int merge(int x, int y)
{
    int px = Find(x), py = Find(y);
    if(px == py) return 0;
    if(siz[px] > siz[py]) swap(px, py);
    p[px] = py, siz[py] += siz[px];
    st[++top] = mp(px, py);
    return 1;
}
In void cancel()
{
    int x = st[top].first, y = st[top].second; --top;
    p[x] = x, siz[y] -= siz[x];
}



分析一下复杂度,对于每一个区间,在线段树上最多只会被分成\(log\)个,因此区间总数量\(mlogm\)个,然后并差集复杂度\(logn\),而遍历线段树的复杂度和并差集操作是独立的,所以不影响,因此总复杂度\(O(mlogmlogn)\)。不过并差集的\(logn\)很小,实际上跑的还是蛮快的。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cctype>
#include<map>
#include<queue>
#include<vector>
#include<assert.h>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 5e3 + 5;
const int maxm = 5e5 + 5;
In ll read()
{
    ll ans = 0;
    char ch = getchar(), las = ' ';
    while(!isdigit(ch)) las = ch, ch = getchar();
    while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    if(las == '-') ans = -ans;
    return ans;
}
In void write(ll x)
{
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar(x % 10 + '0');
}
In void MYFILE()
{
#ifndef mrclr
    freopen("ha.in", "r", stdin);
    freopen("ha.out", "w", stdout);
#endif
}

#define pr pair<int, int>
#define mp make_pair
int n, m, tim[maxn][maxn];
pr q[maxm];

int l[maxm << 2], r[maxm << 2], pos[maxm];
bool vis[maxm << 2];
vector<pr> v[maxm << 2];
In void build(int L, int R, int now)
{
    l[now] = L, r[now] = R;
    if(L == R) {pos[L] = now; return;}
    int mid = (L + R) >> 1;
    build(L, mid, now << 1), build(mid + 1, R, now << 1 | 1);
}
In void update_E(int L, int R, int now, pr E)
{
    if(l[now] == L && r[now] == R) {v[now].push_back(E); return;}
    int mid = (l[now] + r[now]) >> 1;
    if(R <= mid) update_E(L, R, now << 1, E);
    else if(L > mid) update_E(L, R, now << 1 | 1, E);
    else update_E(L, mid, now << 1, E), update_E(mid + 1, R, now << 1 | 1, E);
}


int p[maxn], siz[maxn], top = 0;
pr st[maxm << 2];
In int Find(int x) {return x == p[x] ? x : Find(p[x]);}
In int merge(int x, int y)
{
    int px = Find(x), py = Find(y);
    if(px == py) return 0;
    if(siz[px] > siz[py]) swap(px, py);
    p[px] = py, siz[py] += siz[px];
    st[++top] = mp(px, py);
    return 1;
}
In void cancel()
{
    int x = st[top].first, y = st[top].second; --top;
    p[x] = x, siz[y] -= siz[x];
}

int ans[maxm];
In void dfs(int now)
{
    int cnt = 0;
    for(auto i : v[now]) cnt += merge(i.first, i.second);
    if(l[now] == r[now])
    {
        if(vis[l[now]]) ans[l[now]] = Find(q[l[now]].first) == Find(q[l[now]].second);
        for(int i = 1; i <= cnt; ++i) cancel();
        return;
    }
    dfs(now << 1), dfs(now << 1 | 1);
    for(int i = 1; i <= cnt; ++i) cancel();
}

int main()
{
//  MYFILE();
    n = read(), m = read();
    build(1, m, 1);
    int FLG = 0;
    for(int i = 1; i <= m; ++i)
    {
        int op = read(), x = read(), y = read();
        if(x > y) swap(x, y);
        if(!op) tim[x][y] = i;
        else if(op == 1) update_E(tim[x][y], i, 1, mp(x, y)), tim[x][y] = 0;
        else q[i] = mp(x, y), FLG = vis[i] = 1;
    }
    if(!FLG) return 0;
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= n; ++j) if(tim[i][j]) update_E(tim[i][j], m, 1, mp(i, j));
    for(int i = 1; i <= n; ++i) p[i] = i, siz[i] = 1;
    dfs(1);
    for(int i = 1; i <= m; ++i) if(vis[i]) puts(ans[i] ? "Y" : "N");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/mrclr/p/11049098.html
今日推荐