bzoj 2075: [POI2004]KAG


整天鬼畜題搞搞,感覺葯丸……

這種題出到xjoi模擬題里,太神了……

 

這題的核心在於分割Cograph,嘗試把Cograph的合成過程給求出來。

 

我們將這張圖中的邊定為黑邊,在這張圖的補圖中出現的邊定為白邊,則黑邊和白邊構成了一個完全圖。

1.如果當前這張圖的黑邊是不聯通的,那么可以檢查所有的黑邊構成的聯通塊是不是Cograph,如果都是Cograph,則原圖也為Cograph

2.如果當前這張圖的白邊是不聯通的,那么可以檢查所有的白邊構成的聯通塊是不是Cograph,如果都是Cograph,則原圖也為Cograph

 

3.如果當前這張圖中的白邊黑邊都是聯通的,直接返回該圖不是Cograph

 

這樣做顯然是正確的,但是時間復雜度太高了,每次划分的復雜度是\(O(m)\)的,由於白邊有\(O(n^2)\)條,因此這個做法也是\(O(n^2)\)

 

顯然是會爆炸的……

考慮優化這個做法,我們並不需要枚舉所有白邊,當找到一條白邊時,就將它所連接的兩個白聯通塊合並,合並次數是\(O(n)\)的

因此需要一種支持快速 合並聯通塊、查詢一個聯通塊到另一個聯通塊之間所有邊的數據結構……

 

這里用鏈表維護聯通塊……(為什么不用並查集?因為我要訪問該聯通塊所有的點

 

這樣就可以保證每次查詢的邊一定是不在當前同一個聯通塊中,

查詢的兩個點間要么是黑邊要么是白邊,黑邊只有\(O(m)\)條,由於只有\(O(n)\)次合並,因此掃到的白邊只有\(O(n)\)條,時間復雜度是\(O(n + m)\)的

 

這樣對於一個問題,只需要\(O(n + m)\)就可以把它變成若干個小原問題了。

 

由於Cograph每層的分割至少有\(O(n)\)條連接在白聯通塊之間的黑邊被刪除了,因此這樣分割的層數是\(O(min(m / n, n))\)的

 

總時間復雜度\(O((n + m)\sqrt{m})\)

跑的稍微有點慢啊~

#include <bits/stdc++.h>
#define N 300000
using namespace std;
  
vector <int> bi[N], bn[N];
int T, n, m;
int ai[N];
int nx[N], ne[N], nl[N], tot;
int vis[N], td[N], tt[N], col[N];
int tmp;
void dfs1(int t, int c)
{
    vis[t] = c;
    for (int i = 0; i < bi[t].size(); ++ i)
        if (!vis[bi[t][i]]) dfs1(bi[t][i], c);
}
int solve2(int t);
int solve1(int t)
{
    int nw = tmp + 1;
    for (int p = t; p; p = nx[p]) vis[p] = 0;
    for (int p = t; p; p = nx[p])
        if (!vis[p])
            dfs1(p, vis[p] = ++ tmp);
    for (int p = t; p; p = nx[p])
    {
        if (!tt[vis[p]]) tt[vis[p]] = td[vis[p]] = p;
        else
        {
            nx[td[vis[p]]] = p;
            td[vis[p]] = p;
        }
    }
    for (int i = nw; i <= tmp; ++ i)
    {
        nx[td[i]] = 0;
        if (!solve2(tt[i])) return 0;
    }
    return 1;
}
set <int> S[N];
int test(int a, int b)
{
    return S[a].count(b);
}
int solve2(int t)
{
    if (nx[t] == 0) return 1;
    for (int p = t; p; p = nx[p]) ne[p] = nx[p], nl[p] = p;
    for (int p = t; p; p = ne[p]) nx[p] = 0;
      
    for (int p = t; p; p = ne[p])
    {
        for (int a = p; a; a = nx[a])
        {
            for (int q = ne[p], c = p; q; )
            {
                int bo = 0;
                for (int b = q; b; b = nx[b])
                    if (!test(a, b))
                    {
                        bo = 1;
                        goto haha;
                    }
                haha:
                if (bo)
                {
                    nx[nl[p]] = q;
                    nl[p] = nl[q];
                    nl[q] = 0;
                      
                    ne[c] = ne[q];
                    ne[q] = 0;
                    q = ne[c];
                }
                else
                {
                    c = ne[c];
                    q = ne[q];
                }
            }
        }
    }
    if (ne[t] == 0) return 0;
    for (int p = t; p; p = ne[p])
        for (int q = p; q; q = nx[q])
            col[q] = p, bn[q].clear();
          
    for (int p = t; p; p = ne[p])
        for (int q = p; q; q = nx[q])
            for (int a = 0; a < bi[q].size(); ++ a)
                if (col[bi[q][a]] == col[q]) bn[q].push_back(bi[q][a]);
      
    for (int p = t; p; p = ne[p])
        for (int q = p; q; q = nx[q])
            bi[q] = bn[q];
      
    vector <int> nls;
    for (int p = t; p; p = ne[p]) nls.push_back(p);
    for (int p = 0; p < nls.size(); ++ p)
        if (!solve1(nls[p])) return 0;
    return 1;
}
int main()
{
    //freopen("C.in", "r", stdin);
    scanf("%d", &T);
    while (T --)
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= m; ++ i)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            bi[a].push_back(b); S[a].insert(b);
            bi[b].push_back(a); S[b].insert(a);
        }
        for (int i = 1; i < n; ++ i) nx[i] = i + 1, ne[i] = 0;
        nx[n] = 0;
        if (solve1(1)) puts("TAK"); else puts("NIE");
          
        for (int i = 1; i <= n; ++ i) bi[i].clear(), S[i].clear();
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM