1. 程式人生 > 其它 >HDU4858 專案管理(圖分塊)

HDU4858 專案管理(圖分塊)

目錄

Description

\(n\) 個節點,有 \(m\) 條邊,有 \(Q\) 次操作

\(0\ u\ v\): 節點 \(u\) 的權值增加 \(v\)

\(1\ u\): 輸出與 \(u\) 相連的節點所有節點之和

State

\(1<=n<=10^5\)

\(1<=m<=n+10\)

\(1<=v<=100\)

Input

1
3 2
1 2
1 3
6
0 1 15
0 3 4
1 1
1 3
0 2 33
1 2

Output

4
15
15

Solution

圖中有兩種節點,一種是節點度小於等於 \(\sqrt{m}\) 的,另一種是大於 \(\sqrt{m}\) 的;

而對於操作 $ 0$ 時間複雜度為 \(O(1)\),操作 \(1\) 最壞為 \(O(m)\)

這顯然是不可取的;但是對於第一種節點的查詢操作為 \(O(\sqrt{m})\),如果將第二種節點查詢複雜度降下來的話,複雜度應該是可行的


這時只關心第二種節點,與第二種節點相連的仍然是這兩種節點。

對於一個重結點 \(x\) ,與其相連的節點更新時如果想要波及到 \(x\) 的話,這兩種點都要連線 \(x\),也就是說:

輕節點只要連線重節點,重節點只要連線重節點,在更新時就可以滿足時間上的要求了

在這裡輕節點的度顯然小於等於 \(\sqrt{m}\),而重節點最多有 \(\sqrt{m}\) 個,所以重節點的度也為 \(\sqrt{m}\)


Code

const int N = 1e5 + 5;
 
    int n, m, k, _;
    vector<int> G[N], G2[N];
    int block;
    int sum[N], ans[N];

void clear()
{
    for(int i = 1; i <= n; i ++){
        G[i].clear();
        G2[i].clear();
        sum[i] = ans[i] = 0;
    }
}

signed main()
{
    // IOS;
    rush(){
        sdd(n, m);
        int x, y;
        rep(i, 1, m){
            sdd(x, y);
            G[x].pb(y); 
            G[y].pb(x);
        }
        block = sqrt(m);
        for(int i = 1; i <= n; i ++){
            for(int j = 0; j < G[i].size(); j ++){
                x = G[i][j];
                if(G[x].size() > block) G2[i].pb(x);
            }
        }
        int Q = read();
        for(int k = 1; k <= Q; k ++){
            int opt, u, v;
            sdd(opt, u);
            if(opt == 0){
                sd(v);
                ans[u] += v;
                for(auto it : G2[u]){
                    sum[it] += v;
                } 
            }
            else{
                int res = 0;
                if(G[u].size() <= block){
                    for(auto it : G[u]){
                        res += ans[it];
                    }
                }
                else{
                    res = sum[u];
                }
                pd(res);
            }
        }
        clear();
    }
    // PAUSE;
    return 0;
}