zoukankan      html  css  js  c++  java
  • [***]HZOJ 哪一天她能重回我身边

    %%%神仙题。

    居然是图论,我还一直以为是二分图或者啥数据结构。

    直接说正解了,将数看作节点,牌看做边,从牌的正面的数想反面连边权为1的边,反面向正面连边权为0的边(注意用到成对存储的技巧,之后会非常巧妙地用到),可以发现就是要求反转几条边可以使每个点的出读小于等于1。那么每个联通图只可能是树或基环树。可以先dfs判断求出每个联通图的点数np和边数ne,若ne/2(双向边)>np,那么这个联通图不合法直接输出-1 -1即可。

     1 void dfs(int x,int fa)
     2 {
     3     vi[x]=1;np++;
     4     for(int i=f(x);i;i=n(i))
     5     {
     6             ne++;
     7         if(v(i)!=fa)
     8             if(!vi[v(i)])dfs(v(i),x);
     9     }
    10 }
    11 bool pd()
    12 {
    13     for(int i=1;i<=n*2;i++)
    14     if(!vi[i])
    15     {
    16         np=ne=0,dfs(i,0);
    17         if(np<ne/2)return 1;
    18     }
    19     return 0;
    20 }
    代码实现

    接下来考虑他是树的情况:

    对于确定的跟节点,翻转的边的个数就是将所有点指向父亲节点(可以动手画一下),可以用树形dp求得。但是要枚举根节点吗?其实可以用到二次扫描和换根法,设以x为根要反转的边数为f[x],那么其实f[son]可以用f[x]更新:如果x->son的边权为1,则f[son]=f[x]-1,否则f[son]=f[x]+1.这样我们就解决了树的情况。

     1 int f[MAXN],st,en,ned;
     2 void dfs1(int x,int fa)
     3 {
     4     v[x]=1;f[x]=0;
     5     for(int i=f(x);i;i=n(i))
     6     if(v(i)!=fa)
     7     {
     8         if(!v[v(i)])
     9         {
    10             dfs1(v(i),x);
    11             f[x]+=f[v(i)]+w(i);
    12         }
    13         else st=u(i),en=v(i),ned=i;
    14     }
    15 }
    16 int f2[MAXN];
    17 vector<int> tem;
    18 void dfs2(int x,int fa)
    19 {
    20     tem.push_back(f2[x]);
    21     for(int i=f(x);i;i=n(i))
    22     if(v(i)!=fa && i!=ned && i!=(ned^1))
    23     {
    24         if(w(i))f2[v(i)]=f2[x]-1;
    25         else    f2[v(i)]=f2[x]+1;
    26         dfs2(v(i),x);
    27     }
    28 }
    代码实现

    下面看基环树:

    在dfs时找出环上的随机一条边记录,将它去掉按树处理,最后在考虑这条边的影响。那么边的成对储存就有用了,将边的编号%2就是它从u指向v的权值。

    1                 ned%=2;
    2                 if(f2[st]+ned==f2[en]+(ned^1))minn=2;
    3                 else minn=1;
    4                 ans+=min(f2[st]+ned,f2[en]+(ned^1));
    代码实现
      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<vector>
      6 #define MAXN 200010
      7 #define mod 998244353
      8 #define LL long long
      9 #define int LL
     10 #define ma(x) memset(x,0,sizeof(x))
     11 using namespace std;
     12 struct edge
     13 {
     14     int u,v,w,nxt;
     15     #define u(x) ed[x].u
     16     #define v(x) ed[x].v
     17     #define w(x) ed[x].w
     18     #define n(x) ed[x].nxt
     19 }ed[MAXN*2];
     20 int first[MAXN],num_e=1;
     21 #define f(x) first[x]
     22 int T,n;
     23 
     24 int np,ne;
     25 bool v[MAXN],vi[MAXN];
     26 void dfs(int x,int fa)
     27 {
     28     vi[x]=1;np++;
     29     for(int i=f(x);i;i=n(i))
     30     {
     31             ne++;
     32         if(v(i)!=fa)
     33             if(!vi[v(i)])dfs(v(i),x);
     34     }
     35 }
     36 bool pd()
     37 {
     38     for(int i=1;i<=n*2;i++)
     39     if(!vi[i])
     40     {
     41         np=ne=0,dfs(i,0);
     42         if(np<ne/2)return 1;
     43     }
     44     return 0;
     45 }
     46 int f[MAXN],st,en,ned;
     47 void dfs1(int x,int fa)
     48 {
     49     v[x]=1;f[x]=0;
     50     for(int i=f(x);i;i=n(i))
     51     if(v(i)!=fa)
     52     {
     53         if(!v[v(i)])
     54         {
     55             dfs1(v(i),x);
     56             f[x]+=f[v(i)]+w(i);
     57         }
     58         else st=u(i),en=v(i),ned=i;
     59     }
     60 }
     61 int f2[MAXN];
     62 vector<int> tem;
     63 void dfs2(int x,int fa)
     64 {
     65 //    v[x]=1;
     66     tem.push_back(f2[x]);
     67     for(int i=f(x);i;i=n(i))
     68     if(v(i)!=fa && i!=ned && i!=(ned^1))
     69     {
     70         if(w(i))f2[v(i)]=f2[x]-1;
     71         else    f2[v(i)]=f2[x]+1;
     72 //        if(!v[v(i)])
     73         dfs2(v(i),x);
     74     }
     75 }
     76 inline void add(int u,int v,int w);
     77 signed main()
     78 {
     79 //    freopen("back5.in","r",stdin);
     80 //    freopen("1.out","w",stdout);
     81     
     82     cin>>T;
     83     while(T--)
     84     {
     85         ma(f);ma(f2);ma(v);ma(vi);ma(first);num_e=1;tem.clear();
     86         scanf("%lld",&n);
     87         int a,b;
     88         for(int i=1;i<=n;i++)
     89         {
     90             scanf("%lld%lld",&a,&b);
     91             add(a,b,1);add(b,a,0);
     92         }
     93         if(pd()){puts("-1 -1");continue;}
     94         int minn=0,ans=0,ans2=1;
     95         for(int i=1;i<=n*2;i++)
     96         if(!v[i])
     97         {    
     98             st=en=ned=-1;tem.clear();minn=0;
     99             dfs1(i,0);
    100             f2[i]=f[i];
    101             dfs2(i,0);
    102             if(st==-1)
    103             {
    104                 sort(tem.begin(),tem.end());
    105                 for(int j=0;j<tem.size();j++)
    106                 if(tem[j]==tem[0])minn++;
    107                 else break;
    108                 ans+=tem[0];
    109             }
    110             else
    111             {
    112                 ned%=2;
    113                 if(f2[st]+ned==f2[en]+(ned^1))minn=2;
    114                 else minn=1;
    115                 ans+=min(f2[st]+ned,f2[en]+(ned^1));
    116             }
    117             ans2=(ans2*minn)%mod;
    118         }
    119         printf("%lld %lld
    ",ans,ans2);
    120     }
    121 }
    122 inline void add(int u,int v,int w)
    123 {
    124     ++num_e;
    125     u(num_e)=u;
    126     v(num_e)=v;
    127     w(num_e)=w;
    128     n(num_e)=f(u);
    129     f(u)=num_e;
    130 }
    完整代码
  • 相关阅读:
    win7每天出现taskeng.exe进程的解决方案
    hibernate插入中文字段时,无法插入数据库
    本页面用来演示如何通过JS SDK,创建完整的QQ登录流程,并调用openapi接口
    不同项目之间的通信
    404错误、405错误、500错误出错原因
    linux 下启动tomcat 时没有执行权限
    webservice文件上传下载(byte[] 实现方式)
    文件路径获取
    单个文件复制
    myeclipse svn重新定位 本地文件 svn 重新定位
  • 原文地址:https://www.cnblogs.com/Al-Ca/p/11219279.html
Copyright © 2011-2022 走看看