题意简述
给定一个图,点数1e5,边数1e6。定义一个“半联通”的子图为:对于任意点 ( u , v ) (u,v) (u,v),满足: u u u能到 v v v,或 v v v能到 u u u。求最大的半联通子图点数,并求出满足像这样最大的解有多少个。
思路
(这个题是我做志愿者的时候做的。。。背着老师偷偷做题真tm爽。。。)
看起来这个“半联通”和“强连通”有点像,只不过一个是且,一个是或。但就是因为这个且改成或,就不好做了。
但是我们想一想,一个强连通分量是不是一个半联通子图?(woc我个智障想了半天才想到这一点)是的!
所以我们把强连通分量缩点即珂。由于要求最大点数,所以缩点时要维护这个分量里的点数。
然后图就变成了一个 D A G DAG DAG。在 D A G DAG DAG里就好做很多了。而且有一个明显的结论: D A G DAG DAG中的半联通子图一定是一个链。
如果你不知道为啥,看这里的解释
此时显然我们选择了两条链。但是这两个红色的点就无法到达了,两边都不能到达,所以连“半联通”也不算。所以我们只能选择一条链。
然后就变成了带权的最长链问题了。 d p dp dp即珂。
然后求个数?套路的,我们都 d p dp dp了,在能取到相同的 d p dp dp值时,用 + = += +=记录个数即珂。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{
#define N 100100
#define MEM(x,a) memset(x,a,sizeof(x))
#define CLS(x) memset(x,0,sizeof(x))
class Graph
{
public:
int *head;
int EdgeCount;
struct Edge
{
int To,Label,Next;
}*Ed;
int MAX;
void SET(int len)
{
MAX=(len<<1)+100;
Ed=new Edge[MAX];
head=new int[MAX];
memset(head,-1,sizeof(int)*MAX);
memset(Ed,-1,sizeof(Edge)*MAX);
EdgeCount=0;
}
void clear()
{
memset(</