zoukankan      html  css  js  c++  java
  • bzoj4153 [Ipsc2015]Familiar Couples

    Description

    有n对夫妇,一开始夫妇之间互不认识,若两男或两女成为朋友,称他们为"熟人","熟人"关系具有传递性,即若a熟b且b熟c则a熟c.若两组夫妇的丈夫互相为熟人且妻子也相互为熟人则称他们为"熟悉的一对",现在给出q个事件,每个事件会使得两男或两女成为朋友,并在每次事件之后计算"熟悉的一对"的个数.

    Input

    第一行一个数T表示数据组数
    接下来n,q表示对数和事件数
    接下来q行,每行t,a,b,若t=1,表示男a和男b成为朋友,t=2,表示女a和女b成为朋友

    Output

    设当前是第i个操作,y_i为本次事件之后的答案,令z_i=i*y_i,请输出z_1+z_2+...+z_q模10^9+7
    题意简化为维护两个图,支持在一个图中连边和询问有多少点对在两个图中都连通
    用两个并查集分别维护两个图中的连通性,用一个hashmap维护一个n*n的二维数组,f[x][y]表示在并查集1中属于集合x,在并查集2中属于集合y的点的个数
    每次在一个图中连边时,若两侧连通则忽略,不联通则遍历小的一个联通块,通过计算在另一个图中跨过两个联通块的联通块更新答案
    均摊时间复杂度O(Tnlogn)
    #include<cstdio>#include<vector>
    const int P=1e9+7,N=1e6+5;
    inline int read(){
        int x=0,c=getchar();
        while(c>'9'||c<'0')c=getchar();
        while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
        return x;
    }
    inline void exch(int&a,int&b){int c=a;a=b;b=c;}namespace Map{
        const int mx=2939999;
        unsigned int nw=0;
        unsigned int xs[mx],ys[mx],zs[mx],ds[mx];
        inline void clear(){
            nw++;
        }
        inline int get(unsigned int x,unsigned int y,int inc){
            unsigned int w=(x*17+y*53+3)%mx;
            while(ds[w]==nw){
                if(xs[w]==x&&ys[w]==y){
                    int v=zs[w];
                    zs[w]+=inc;
                    return v;
                }
                w+=1237;
                if(w>=mx)w-=mx;
            }
            ds[w]=nw;
            xs[w]=x;ys[w]=y;zs[w]=inc;
            return 0;
        }
    }
    int T,n,m,now=1,Ans,ans;
    int h1[N],h2[N],f1[N],f2[N],sz1[N],sz2[N],nx1[N],nx2[N];
    int t[N],d[N];
    std::vector<int>v1[N],v2[N];
    int main(){
        T=read();
        while(T--){
            n=read();m=read();
            Ans=ans=0;
            Map::clear();
            for(int i=1;i<=n;i++){
                Map::get(i,i,1);
                f1[i]=f2[i]=i;
                v1[i].clear();v2[i].clear();
                v1[i].push_back(i);
                v2[i].push_back(i);
            }
            for(int i=1,op,a,b;i<=m;++i){
                op=read();a=read();b=read();
                ++now;
                if(op==1){
                    if(f1[a]!=f1[b]){
                        if(v1[f1[a]].size()>v1[f1[b]].size())exch(a,b);
                        std::vector<int>&vc=v1[f1[a]];
                        for(int x=0;x<vc.size();x++){
                            int p=vc[x];
                            int f=f2[p];
                            if(d[f]!=now)d[f]=now,ans=(ans+Map::get(f1[p],f,-1)*1ll*Map::get(f1[b],f,1)%P)%P;
                            else Map::get(f1[p],f,-1),Map::get(f1[b],f,1);
                            f1[p]=f1[b];
                            v1[f1[b]].push_back(p);
                        }
                        vc.clear();
                    }
                }else{
                    if(f2[a]!=f2[b]){
                        if(v2[f2[a]].size()>v2[f2[b]].size())exch(a,b);
                        std::vector<int>&vc=v2[f2[a]];
                        for(int x=0;x<vc.size();x++){
                            int p=vc[x];
                            int f=f1[p];
                            if(d[f]!=now)d[f]=now,ans=(ans+Map::get(f,f2[p],-1)*1ll*Map::get(f,f2[b],1)%P)%P;
                            else Map::get(f,f2[p],-1),Map::get(f,f2[b],1);
                            f2[p]=f2[b];
                            v2[f2[b]].push_back(p);
                        }
                        vc.clear();
                    }
                }
                Ans=(Ans+ans*1ll*i%P)%P;
            }
            printf("%d
    ",Ans);
        }
        return 0;
    }
  • 相关阅读:
    基于 IAR 修改工程名称
    Baidu IoT Study
    msp430f5438a Information Flash Seg Write -- Chapter
    MFC 编辑框内容更新方法以及滚动条设置
    通过打开按钮打开文件和通过左键移动打开文件并计算crc
    移动文件并将文件路径显示到编辑框内
    Aritronix Virtual Device 运行
    将一个char类型的数转换成曼切斯特数
    数组中重复的数字
    平衡二叉树
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5328985.html
Copyright © 2011-2022 走看看