• 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$很小,实际上跑的还是蛮快的。 ```c++ #include #include #include #include #include #include #include #include #include #include #include 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 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;
    }

  • 相关阅读:
    wikioi 1514 and ZJOI2006 书架
    HDU 4762 Cut the Cake(公式)
    HDU 4762 Cut the Cake(公式)
    呵呵,cnblog排名进4000了,留念一下!
    呵呵,cnblog排名进4000了,留念一下!
    电子书下载:C# Database Basics
    电子书下载:C# Database Basics
    (原創) 如何在Nios II顯示8位數的七段顯示器? (SOC) (Nios II) (SOPC Builder) (DE2-70)
    (原創) 如何在Nios II顯示8位數的七段顯示器? (SOC) (Nios II) (SOPC Builder) (DE2-70)
    部署GlusterFS及Heketi
  • 原文地址:https://www.cnblogs.com/mrclr/p/11049098.html
Copyright © 2020-2023  润新知