zoukankan      html  css  js  c++  java
  • bzoj 4298 [ONTAK2015]Bajtocja——哈希+启发式合并

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4298

    题面:

      给定d张无向图,每张图都有n个点。一开始,在任何一张图中都没有任何边。接下来有m次操作,每次操作会给出a,b,k,意为在第k张图中的点a和点b之间添加一条无向边。你需要在每次操作之后输出有序数对(a,b)的个数,使得1<=a,b<=n,且a点和b点在d张图中都连通。

      第一行包含三个正整数d,n,m(1<=d<=200,1<=n<=5000,1<=m<=1000000),依次表示图的个数,点的个数和操作的个数。
      接下来m行,每行包含三个正整数a,b,k(1<=a,b<=n,1<=k<=d),依次描述每一个操作。
      输出m行m个正整数,依次表示每次操作之后满足条件的有序数对(a,b)的个数。

    与连通性有关,那么就是并查集咯。

    但在一个图里连通了两个点集之后,难道要遍历该点集所有点对,看看在其他图里是否连通?

    1.启发式合并。那么对答案的影响,可以考虑落在 “新加入该点集” 的那些点上。

    2.考虑 “与一个点在 d 张图里都连通的点的个数” 。

      连通意味着处在同一个连通块中。那么记录每个点在 d 张图中分别属于哪些连通块,这形成一个字符串。

      哈希记录某个字符串对应的点数即可。

    需要用哈希表,而且消失的哈希值要从哈希表里删除,才能不超时。即使这样,自己还是平均时间的两倍。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #define ll long long
    #define ull unsigned long long
    #define pb push_back
    using namespace std;
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    int g[20];
    void wrt(ll x)
    {
      if(!x){puts("0");return;}
      int t=0;
      while(x)g[++t]=x%10,x/=10;
      for(int i=t;i;i--)putchar(g[i]+'0');puts("");
    }
    const int N=5005,M=205,bs=10009,M2=N*M*3;
    int n,m,D,fa[N][M],siz[N][M],ct[M2];
    ll ans; ull bin[M],hs[N];
    vector<int> vt[N][M];
    namespace H{
      const int md=3e7;
      int hd[md],xnt,nxt[M2]; ull to[M2];
      int get(ull x)
      {
        int h=x%md;
        for(int i=hd[h];i;i=nxt[i])
          if(to[i]==x)return i;
        to[++xnt]=x; nxt[xnt]=hd[h]; hd[h]=xnt;
        return xnt;
      }
      void del(ull x)
      {
        int h=x%md;
        if(to[hd[h]]==x){hd[h]=nxt[hd[h]];return;}
        for(int i=hd[h],lst=0;i;lst=i,i=nxt[i])
          if(to[i]==x){nxt[lst]=nxt[i];break;}
      }
    }
    int main()
    {
      D=rdn();n=rdn();m=rdn();
      bin[0]=1;for(int i=1;i<=D;i++)bin[i]=bin[i-1]*bs;
      for(int i=1;i<=n;i++)
        {
          for(int j=1;j<=D;j++)
        {
          fa[i][j]=i; siz[i][j]=1;
          vt[i][j].pb(i); hs[i]+=i*bin[j];
        }
          ct[H::get(hs[i])]++;
        }
      ans=n;
      for(int i=1,u,v,d;i<=m;i++)
        {
          u=rdn();v=rdn();d=rdn();
          u=fa[u][d]; v=fa[v][d];
          if(u==v){wrt(ans);continue;}
          if(siz[u][d]<siz[v][d])swap(u,v);
          int tot=siz[u][d];
          siz[u][d]+=siz[v][d]; vt[u][d].resize(siz[u][d]);
          ull tmp=(u-v)*bin[d];
          for(int j=0,cr;j<siz[v][d];j++)
        {
          cr=vt[v][d][j]; fa[cr][d]=u; vt[u][d][tot++]=cr;
          ull x=hs[cr],y=hs[cr]+tmp; hs[cr]+=tmp;
          int t0=H::get(x),t1=H::get(y);
          ct[t0]--; ans-=ct[t0]*2; ans+=ct[t1]*2; ct[t1]++;
        }
          vector<int> ().swap(vt[v][d]);
          wrt(ans);
        }
      return 0;
    }
    View Code
  • 相关阅读:
    iOS开发~UI布局(二)storyboard中autolayout和size class的使用详解
    iOS开发~UI布局(一)初探Size Class
    OC登陆界面登陆按钮动画
    Git学习 --> 个人常用命令add,commit以及push
    Git使用之设置SSH Key
    【iOS开发】多屏尺的自动适配 AutoLayout (纯代码方式)
    iOS网络检测Reachability 使用 Demo,可检测2、3、4G
    iOS提醒用户进入设置界面进行重新授权通知定位等功能
    iOS中 @synthesize 和 @dynamic 区别
    iOS 开发笔记
  • 原文地址:https://www.cnblogs.com/Narh/p/11084723.html
Copyright © 2011-2022 走看看