[***]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\n",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 }
完整代码

 

posted @ 2019-07-21 21:27  Al_Ca  阅读(259)  评论(0编辑  收藏  举报
ヾ(≧O≦)〃嗷~