bzoj 4424: Cf19E Fairy && codeforces 19E. Fairy【树形dp】

参考:https://blog.csdn.net/heheda_is_an_oier/article/details/51131641 这个找奇偶环的dp1真是巧妙,感觉像tarjan一样

首先分情况讨论,如果没有奇环,每条边都可以删;如果有一个奇环,奇环上隋边山;否则,删被所有奇环覆盖且没被任何一个偶环覆盖的边

那么重点就是怎样找到所有的奇环和偶环

用树形dp来搞,设f[i]记录经过第i条边的奇环数,g[i]记录经过第i条边的偶环数,因为是边的编号而存的是双向边,所以dp的时候用i>>1表示

然后随便dfs出一棵树,对于其他的返祖边如果是奇环的话f[i]++,偶环同理,并且加到父亲上

然后如果是返祖边的返祖边要减掉,因为已经统计过了

#include<iostream>
#include<cstdio>
using namespace std;
const int N=2000005;
int n,m,cnt=1,h[N],con,ans[N],f[N],g[N],p[N],q[N],top,tot;
bool v[N];
struct qwe
{
    int ne,to;
}e[N];
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>‘9‘||p<‘0‘)
    {
        if(p==‘-‘)
            f=-1;
        p=getchar();
    }
    while(p>=‘0‘&&p<=‘9‘)
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
void add(int u,int v)
{
    cnt++;
    e[cnt].ne=h[u];
    e[cnt].to=v;
    h[u]=cnt;
}
void dfs(int u,int fa)
{
    v[u]=1;
    p[u]=++top;
    for(int i=h[u];i;i=e[i].ne)
        if(q[i]!=-1)
        {
            if(!v[e[i].to])
            {
                q[i]=q[i^1]=-1;
                dfs(e[i].to,i>>1);
                f[fa]+=f[i>>1];
                g[fa]+=g[i>>1];
            }
            else
            {
                if(q[i]==1)
                    f[fa]--;
                if(q[i]==2)
                    g[fa]--;
                if(q[i]==0)
                {
                    if((p[u]-p[e[i].to])&1)
                        g[fa]++,q[i]=q[i^1]=2;
                    else
                        f[fa]++,q[i]=q[i^1]=1,con++;
                }
            }
        }
    top--;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        add(x,y),add(y,x);
    }
    for(int i=1;i<=n;i++)
        if(!v[i])
            dfs(i,0);
    if(con==0)
    {
        tot=m;
        for(int i=1;i<=m;i++)
            ans[i]=i;
    }
    else
    {
        for(int i=1;i<=m;i++)
            if((f[i]==con&&g[i]==0)||(con==1&&q[i<<1]==1))
                ans[++tot]=i;
    }
    printf("%d\n",tot);
    for(int i=1;i<=tot;i++)
        printf("%d ",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/lokiii/p/9351741.html

时间: 2024-10-11 16:35:06

bzoj 4424: Cf19E Fairy && codeforces 19E. Fairy【树形dp】的相关文章

BZOJ 1040 ZJOI 2008 骑士 基环树林+树形DP

题目大意:有一些骑士,他们每个人都有一个权值.但是由于一些问题,每一个骑士都特别讨厌另一个骑士.所以不能把他们安排在一起.求这些骑士所组成的编队的最大权值和是多少. 思路:首先貌似是有向图的样子,但是一个人讨厌另一个人,他们两个就不能在一起,所以边可以看成是无向的. n个点,n条无向边,好像是一颗基环树.但其实这是一个基环树林,因为题中并没有说保证图一定联通. 然后就可以深搜了,处理出每一个联通块.其实每一个联通块就是一个基环树,在这个基环树上进行树形DP.求出最大值,然后累加到答案上.答案要开

[BZOJ 1017][JSOI2008]魔兽地图DotR(树形Dp)

Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allstars.DotR里面的英雄只有一个属性——力量.他们需要购买装备来提升自己的 力量值,每件装备都可以使佩戴它的英雄的力量值提高固定的点数,所以英雄的力量值等于它购买的所有装备的力 量值之和.装备分为基本装备和高级装备两种.基本装备可以直接从商店里面用金币购买,而高级装备需要用

Choosing Capital for Treeland CodeForces - 219D (树形DP)

传送门 The country Treeland consists of n cities, some pairs of them are connected with unidirectional roads. Overall there are n - 1 roads in the country. We know that if we don't take the direction of the roads into consideration, we can get from any

CodeForces 735E(树形DP)

CodeForces 735E Ostap and Tree 题意:给一棵树,需要给树上的一些节点上色,要求任意节点在距离为k的范围以内至少有一个被染色的点,求方案数. 思路:之前看别人代码,感觉好短,题解也好简略,感觉不是很明朗,现在终于感觉自己看懂一点了,来留一发. 用 dp[x][i] 记录离节点 x 最近的一个被染色的点距 x 的距离为 i ,对于其子树 dp[y][j] ,如果 i+j<=2*k,则此时 min(i,j)<=k,即在此时是成立的,因此把值存入最近的染色点f[min(i

BZOJ 2097 Exercise 奶牛健美操 二分答案+树形DP+贪心

题目大意:给定一棵树,可以删掉k条边,求删掉后森林中所有树直径的最大值的最小值 最大值最小,典型的二分答案 此题我们二分树的直径,每次二分DFS一次,对于每个节点统计出所有子树删边后的dis,排序,贪心删掉最大的,直到最大的两个子树相加不会超过二分的答案为止 时间复杂度O(nlog^2n) 老子的二分居然写挂了...桑不起啊啊啊啊 #include<cstdio> #include<cstring> #include<iostream> #include<algo

【BZOJ】2435: [Noi2011]道路修建(树形dp)

http://www.lydsy.com/JudgeOnline/problem.php?id=2435 我怎么感觉那么水.. 坑的是,dfs会爆...好吧..用bfs.. #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #include <queue&

BZOJ 4316: 小C的独立集 仙人掌 + 树形DP

4316: 小C的独立集 Time Limit: 10 Sec  Memory Limit: 128 MB Description 图论小王子小C经常虐菜,特别是在图论方面,经常把小D虐得很惨很惨. 这不,小C让小D去求一个无向图的最大独立集,通俗地讲就是:在无向图中选出若干个点,这些点互相没有边连接,并使取出的点尽量多. 小D虽然图论很弱,但是也知道无向图最大独立集是npc,但是小C很仁慈的给了一个很有特点的图: 图中任何一条边属于且仅属于一个简单环,图中没有重边和自环.小C说这样就会比较水了

BZOJ 2159: Crash 的文明世界(树形dp+第二类斯特林数+组合数)

题意: 给定一棵 \(n\) 个点的树和一个常数 \(k\) , 对于每个 \(i\) , 求 \[\displaystyle S(i) = \sum _{j=1} ^ {n} \mathrm{dist}(i, j)^k\] \(n ≤ 50000, k ≤ 150\) 题解 : 先划划那个 \(S(i)\) 的式子 我们需要知道一个化 \(x^n(n \ge 0)\) 的东西qwq \[\displaystyle x^n=\sum_{k=0}^{n}\begin{Bmatrix} n \\ k

bzoj 2427: [HAOI2010]软件安装【tarjan+树形dp】

一眼最大权闭合子图,然后开始构图,画了画之后发现我其实是个智障网络流满足不了m,于是发现正确的打开方式应该是一眼树上dp 然后仔细看了看性质,发现把依赖关系建成图之后是个奇环森林,这个显然不能直接dp 发现这个环要选的话只能选整个环,所以tarjan缩一下点,然后再跑树上背包就行了 #include<iostream> #include<cstdio> #include<vector> #include<cstring> using namespace st