题目链接

Problem Description

In the mathematical discipline of graph theory, a bipartite graph is a graph whose vertices can be divided into two disjoint sets U and V (that is, U and V are each independent sets) such that every edge connects a vertex in U to one in V. Vertex sets U and V are usually called the parts of the graph. Equivalently, a bipartite graph is a graph that does not contain any odd-length cycles. A matching in a graph is a set of edges without common vertices. A perfect matching is a matching that each vertice is covered by an edge in the set.

Little Q misunderstands the definition of bipartite graph, he thinks the size of U is equal to the size of V, and for each vertex p in U, there are exactly two edges from p. Based on such weighted graph, he defines the weight of a perfect matching as the product of all the edges' weight, and the weight of a graph is the sum of all the perfect matchings' weight.

Please write a program to compute the weight of a weighted ''bipartite graph'' made by Little Q.

Input

The first line of the input contains an integer T(1≤T≤15), denoting the number of test cases.

In each test case, there is an integer n(1≤n≤300000) in the first line, denoting the size of U. The vertex in U and V are labeled by 1,2,...,n.

For the next n lines, each line contains 4 integers vi,1,wi,1,vi,2,wi,2(1≤vi,j≤n,1≤wi,j≤109), denoting there is an edge between Ui and Vvi,1, weighted wi,1, and there is another edge between Ui and Vvi,2, weighted wi,2.

It is guaranteed that each graph has at least one perfect matchings, and there are at most one edge between every pair of vertex.

Output

For each test case, print a single line containing an integer, denoting the weight of the given graph. Since the answer may be very large, please print the answer modulo 998244353.

Sample Input

1

2

2 1 1 4

1 4 2 3

Sample Output

16

题意:

T组测试数据,给出两个集合用以表示顶点,左边为集合U,右边为集合V,每个顶点集合的大小为n,然后有n行输入,第i行的输入v1,w1,v2,w2,表示集合U中的第i个顶点与集合V中的v1,v2顶点分别相连,且两个边的权值为w1,w2。求两个集合的所有完美匹配的权值之和。一个完美匹配的权值为该匹配所有边的权值相乘,且数据保证至少存在一个完美匹配。

分析:

题目保证至少存在一个完美匹配,集合U中所有顶点的度数肯定都等于2,集合V中所有顶点的度数都大于等于1,那么对于V中度数为1的点,它们对所有完美匹配的权值的贡献w是不变的,因此,我们可以先处理V中度数为1的点。假设V中度数为1的点有k个,那么在U中就需要用k个点来与V中的k个度数为1的点匹配(这里可能不太好理解为什么U中也是k个点,解释一下原因,当V中度为1的点在集合U中到该边所对应的点u1之后,u1所对应的度也会减1,我们此时还要判断u1的度是否为1,为1 的话也要将此点进行相应的度为1的处理),然后U和V中都剩下m个点,m=(n-k)。此时我们可以知道U和V中所有点的度数都大于等于2了。(U中会存在度数为1的点吗?不存在的。U中顶点的度数只有我们在处理V中顶点的时候才会改变,那么当我们在处理V中度数为1的顶点N的时候,说明U中只有一个顶点M跟N相连,此时的处理只涉及N和M,所以U中别的顶点的度数还是跟初始一样。)继续,U中m个顶点的度数都是2,那么V中m个顶点的总度数就是2*m,又因为此时V中m个顶点的度数都大于等于2,那么我们可以知道V中m个顶点的度数都是2。此时我们可以发现,U∪V中的所有顶点的度数都是偶数,当完美匹配完成后,此时图中必然存在欧拉回路,也就是环。

对于一个环中,如O0->O1->O2->O3->O0,我们可以理解为(1)O0与O1匹配,O2和O3匹配,(2)O1和O2匹配,O3和O0匹配,也就是说,对于一个已经完成的匹配,它只存在两种方案。那么我们就可以在一个环中,通过枚举起点O0和O1来找出当前环的两种匹配权值X1,Y1。由于图中可能存在多个环,我们需要枚举U中m个点来找出所有的环,一个环对于结果的贡献值是common(X1+Y1);那么P个环就是common(X1+Y1)(X2+Y2)....*(XP+YP)=ans

ans就是最后的结果了。

代码:

#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353;
const int N = 300000 + 10;
struct Edge
{
int nxt, to, w;///分别表示下一条边的编号,本边的终点,本边的权重
bool mrk;///一个标记
} e[N*4];
int T, n, head[N*2], cnt, deg[N*2], used[N*2];///deg存储每个点的度,used标记的是某一条边有没有被访问过
long long part[2];
void addedge(int u, int v, int w)///建立边之间的联系的话用的是头插法
{
e[++cnt].nxt = head[u];///指向上一条由节点u指出的边
e[cnt].to = v;
e[cnt].w = w;
e[cnt].mrk = 0;
head[u] = cnt;///改变头指针的值
}
void dfs(int cur, int idx)
{
used[cur] = 1;
for(int i=head[cur]; i; i=e[i].nxt)
{
if(e[i].mrk) continue;
e[i].mrk = e[i^1].mrk = 1;
(part[idx] *= e[i].w) %= mod;
dfs(e[i].to, 1-idx);
}
}
int main()
{
scanf("%d", &T);
while(T-- && scanf("%d", &n)!=EOF)
{
memset(head, 0, sizeof(head));
memset(deg, 0, sizeof(deg));
memset(used, 0, sizeof(used));
cnt = 1;
///将集合U中的点的编号看作1~n,集合V中的点的编号看作n+1~2*n
for(int u=1, v, w; u<=n; u++)
for(int i=1; i<=2; i++)
{
scanf("%d%d", &v,&w);
addedge(u, v+n, w);
addedge(v+n, u, w);
deg[u]++;
deg[v+n]++;
}
long long ans = 1;
queue<int> que;
for(int v=n+1; v<=n+n; v++) ///集合V里面才可能会有度为1的边
if(deg[v] == 1)
que.push(v);
while(!que.empty())///这样的话整个while循环下来,集合U和集合V里面的度为1的边都去掉了,只剩下度为2的边
{
int v = que.front();
que.pop();
used[v] = 1;
for(int i=head[v]; i; i=e[i].nxt)
{
if(e[i].mrk) continue;
e[i].mrk = e[i^1].mrk = 1;///相当于标记的是同一条边,因为每一条边都是分两个方向存下来的
used[ e[i].to ] = 1;
(ans *= e[i].w) %= mod;
for(int j=head[ e[i].to ]; j; j=e[j].nxt)///再从这个终点开始寻找,遇到变化后度为1的边,就把他们处理掉
{
e[j].mrk = e[j^1].mrk = 1;
deg[e[j].to]--;
if(deg[ e[j].to ] == 1) que.push(e[j].to);
}
}
}
///此时两个集合中都只有度为2的点,且两个集合的度的个数还相等
for(int u=1; u<=n; u++)
{
if(used[u]) continue;
part[0] = part[1] = 1;
dfs(u, 0);
(ans *= (part[0]+part[1]) % mod) %= mod;
}
printf("%lld\n", ans);
}
return 0;
}

2017 ACM暑期多校联合训练 - Team 4 1007 HDU 6073 Matching In Multiplication (模拟)的更多相关文章

  1. 2017 ACM暑期多校联合训练 - Team 4 1012 HDU 6078 Wavel Sequence (模拟)

    题目链接 Problem Description Have you ever seen the wave? It's a wonderful view of nature. Little Q is a ...

  2. 2017 ACM暑期多校联合训练 - Team 9 1008 HDU 6168 Numbers (模拟)

    题目链接 Problem Description zk has n numbers a1,a2,...,an. For each (i,j) satisfying 1≤i<j≤n, zk gen ...

  3. 2017 ACM暑期多校联合训练 - Team 5 1008 HDU 6092 Rikka with Subset (找规律)

    题目链接 Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, s ...

  4. 2017 ACM暑期多校联合训练 - Team 3 1008 HDU 6063 RXD and math (莫比乌斯函数)

    题目链接 Problem Description RXD is a good mathematician. One day he wants to calculate: ∑i=1nkμ2(i)×⌊nk ...

  5. 2017ACM暑期多校联合训练 - Team 8 1008 HDU 6140 Hybrid Crystals (模拟)

    题目链接 Problem Description Kyber crystals, also called the living crystal or simply the kyber, and kno ...

  6. 2017ACM暑期多校联合训练 - Team 4 1004 HDU 6070 Dirt Ratio (线段树)

    题目链接 Problem Description In ACM/ICPC contest, the ''Dirt Ratio'' of a team is calculated in the foll ...

  7. 2017ACM暑期多校联合训练 - Team 9 1005 HDU 6165 FFF at Valentine (dfs)

    题目链接 Problem Description At Valentine's eve, Shylock and Lucar were enjoying their time as any other ...

  8. 2017ACM暑期多校联合训练 - Team 9 1010 HDU 6170 Two strings (dp)

    题目链接 Problem Description Giving two strings and you should judge if they are matched. The first stri ...

  9. 2017ACM暑期多校联合训练 - Team 8 1006 HDU 6138 Fleet of the Eternal Throne (字符串处理 AC自动机)

    题目链接 Problem Description The Eternal Fleet was built many centuries ago before the time of Valkorion ...

随机推荐

  1. CDN问题

    名称解释:正反向解析 主辅服务器 domain zone 记录:SOA.NS.A.CNAME.PRT.MX DNS配置文件中各字段作用,如TTL DNS端口号? TCP53和UDP53使用场合 Lin ...

  2. web.py 笔记

    1.涉及到id=‘id’的情况,需要加入  vars=locals()  ,因为id在python里有id() 函数 db.delete('entries', where = 'id = $id', ...

  3. Android自定义XML属性以及遇到的命名空间的问题

    转载请注明出处:http://www.cnblogs.com/kross/p/3458068.html 最近在做一些UI,很蠢很蠢的重复写了很多代码,比如一个自定义的UI Tab,由一个ImageVi ...

  4. HTTP协议 结构,get post 区别(阿里面试)

    如果需要想了解相关的TCP的协议结构,底层架构,以及每次面试必问的三次握手,四次挥手可以 参考:TCP协议详解7层和4层解析(美团面试,阿里面试) 尤其是三次握手,四次挥手 具体发送的报文和状态都要掌 ...

  5. 【设计模式】C++中的单例模式

    讲解来自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&id=4281275&uid=26611383 由于使用了POSIX函 ...

  6. 51nod 1503 猪和回文(多线程DP)

    虚拟两个点,一个从左上角开始走,一个从右下角开始走,定义dp[i][j][k]表示走了i步后,第一个点横向走了j步,第二个点横向走了k步后形成的回文方法种数. 转移方程显然可得,然后滚动数组搞一搞. ...

  7. Openssl的编译安装以及Vs2012上环境搭建教程

    Openssl的编译安装以及Vs2012上环境搭建教程 一.Openssl的编译安装 一.准备工作 1.Openssl下载地址:https://www.openssl.org/source/ 2.Ac ...

  8. 【Visual Installer】如何读取与写入注册表信息

    引入:using Microsoft.Win32; (1)读取注册表信息 代码: RegistryKey rsg = null; rsg = Registry.LocalMachine.OpenSub ...

  9. 解决:LNMP架构下访问php页面出现500错误

    默认情况下,如果被访问的php脚本中包含语法错误,服务器会返回一个空的“200 ok”页面 在php.ini中的fastcgi.error_header选项允许在这种情况下产生一个HTTP错误码 以使 ...

  10. spark core (二)

    一.Spark-Shell交互式工具 1.Spark-Shell交互式工具 Spark-Shell提供了一种学习API的简单方式, 以及一个能够交互式分析数据的强大工具. 在Scala语言环境下或Py ...