牛客多校graph games(部分分塊+哈希)

https://ac.nowcoder.com/acm/contest/883/A

題目大意,給出一個無向圖,設S(x)表示x的臨近點集合,臨近點即通過一條邊直接相連的點。有兩種操作,1是把邊集合(讀入順序)從l到r的邊狀態反轉(相連變斷開,斷開變相連),2是詢問兩個點的臨近集是否相等。

這裏首先涉及到的一個難點是如何表示臨近集,我們採用異或哈希的方式,首先爲所有點分配一個隨機權值,這裏用到了一個新版的隨機函數

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
for(int i=1;i<=n;i++)
    val[i]=rng();

接下來我們把某個點的所有臨近點的權值異或起來,作爲它的臨近集表示。異或哈希的大概原理是,原始權值在每個bit上01的概率相等,而異或過程對於每個bit產生01的概率也是等價的,所以能保證隨機性。這個問題解決後,就能以O(1)時間判定臨近集的相等。

接下來考慮如何維護翻轉,一個簡單的分塊考慮是,對邊集分塊,最開始計算出每個塊對每個點的影響(add數組)(O(m^1.5)),然後對於1操作,標記塊的翻轉,零碎的邊直接計算出來;對於2操作,把所有翻轉的塊中對該點的影響都異或到現有答案上。這樣兩個操作的複雜度都是O(m^0.5),只可惜這樣會超時,由於是多組數據,而我們在每組數據中都要對add數組進行整體清零,這個複雜度是m^0.5*n的,三四組數據估計就不行了。

所以考慮縮減add數組,我們發現,如果一個點的度數比較小,那麼在計算它的臨近集時可以挨個枚舉相連的邊,複雜度是和度數成正比的。因而我們考慮,只把度數大於sqrt(m)的點用add數組維護,這樣的點總共不會超過2*sqrt(m)個。剩下的小點需要再維護一下零碎邊的翻轉性(e數組),同時塊的翻轉標記也會影響到它。

ps分塊題的細節真的一不留神就寫錯……不過思路直接還是挺容易debug的

#include<bits/stdc++.h>
using namespace std;

const int maxn=1e5+2;
const int maxm=2e5+2;

#define ll long long
#define sz(x) (int)x.size()
ll val[maxn],s[maxn];
struct edge{
    int u,v;
}es[maxm];
typedef pair<int,int> pir;
vector<pir> g[maxn];
bool big[maxn];
int cnt,mp[maxn];
ll add[500][1000];
int pos[maxm],tot;
int tag[500],e[maxm];
int n,m,q,t;
string ans;
int main(){
    cin>>t;
    while(t--){
        cin>>n>>m;
        int block=sqrt(m);
        tot=0;
        for(int i=1;i<=m;i++){
            if((i-1)%block==0)
                tot++;
            pos[i]=tot;
        }
        for(int i=1;i<=n;i++)
            g[i].clear();
        for(int i=1;i<=m;i++){
            cin>>es[i].u>>es[i].v;
            g[es[i].u].push_back(pir(es[i].v,i));
            g[es[i].v].push_back(pir(es[i].u,i));
        }
        memset(big,0,sizeof(big));
        cnt=0;
        for(int i=1;i<=n;i++)
            if(sz(g[i])>block){
               big[i]=1;
               mp[i]=++cnt;
            }
        mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
        for(int i=1;i<=n;i++)
            val[i]=rng();


        for(int i=1;i<=tot;i++){
            for(int j=1;j<=cnt;++j)
                add[i][j]=0;
            for(int j=(i-1)*block+1;j<=min(m,i*block);j++){
                int u=es[j].u,v=es[j].v;
                if(big[u])
                    add[i][mp[u]]^=val[v];
                if(big[v])
                    add[i][mp[v]]^=val[u];
            }
        }

        for(int i=1;i<=tot;i++)
            tag[i]=1;
        memset(s,0,sizeof(s));
        memset(e,0,sizeof(e));
        cin>>q;
        ans="";
        while(q--){
            int opt;
            cin>>opt;
            if(opt==1){
                int l,r;
                cin>>l>>r;
                int lp=pos[l],rp=pos[r];
                if(lp<rp){
                    for(int i=lp+1;i<rp;i++)
                        tag[i]^=1;
                    for(int i=l;i<=block*lp;i++){
                        int u=es[i].u,v=es[i].v;
                        e[i]^=1;
                        if(big[u])
                            s[u]^=val[v];
                        if(big[v])
                            s[v]^=val[u];
                    }
                    for(int i=block*(rp-1)+1;i<=min(block*rp,r);i++){
                        int u=es[i].u,v=es[i].v;
                        e[i]^=1;
                        if(big[u])
                            s[u]^=val[v];
                        if(big[v])
                            s[v]^=val[u];
                    }
                }else{
                    for(int i=l;i<=r;i++){
                        int u=es[i].u,v=es[i].v;
                        e[i]^=1;
                        if(big[u])
                            s[u]^=val[v];
                        if(big[v])
                            s[v]^=val[u];
                    }
                }
            }else{
                int u,v;
                cin>>u>>v;
                ll valu=s[u],valv=s[v];
                if(big[u]){
                    for(int i=1;i<=tot;i++){
                        if(tag[i])
                            valu^=add[i][mp[u]];
                    }
                }else{
                    for(int i=0,id,to;i<sz(g[u]);i++){
                        id=g[u][i].second,to=g[u][i].first;
                        if(e[id]^tag[pos[id]]){
                            valu^=val[to];
                        }
                    }
                }
                if(big[v]){
                    for(int i=1;i<=tot;i++){
                        if(tag[i])
                            valv^=add[i][mp[v]];
                    }
                }else{
                    for(int i=0,id,to;i<sz(g[v]);i++){
                        id=g[v][i].second,to=g[v][i].first;
                        if(e[id]^tag[pos[id]]){
                            valv^=val[to];
                        }
                    }
                }
                if(valu==valv){
                    ans+='1';
                }else
                    ans+='0';
            }
        }
        cout<<ans<<endl;
    }
}
/*
1
5 4
1 2
1 3
4 2
4 3
3
2 1 4
1 1 1
2 1 2

*/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章