暴力枚举非树边取值做DP可得75。

注意到每次枚举出一个容斥状态的时候,都要做大量重复操作。

建立虚树,预处理出虚树上两点间的转移系数。也可动态DP解决。

树上倍增、动态DP、虚树DP似乎是这种问题的三种通用解法。

代码不是特别长但极其难写,预处理过程中要考虑各种情况。水平不够只好抄代码。

 #include<cstdio>
#include<algorithm>
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define For(i,x) for (int i=h[x],k; i; i=nxt[i])
using namespace std; const int N=,mod=;
bool mark[N],vis[N],ban[N][];
int n,m,u,v,tot,tim,ans,sz[N],du[N],dv[N],dfn[N],dp[N][],g[N][];
struct P{ int k0,k1; }K[N][]; P operator +(const P &a,const P &b){ return (P){(a.k0+b.k0)%mod,(a.k1+b.k1)%mod}; }
P operator *(const P &a,int x){ return (P){int(1ll*a.k0*x%mod),int(1ll*a.k1*x%mod)}; } struct Edge{
int cnt,h[N],to[N<<],nxt[N<<];
P val[][];
void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
void add(int u,int v,const P &a,const P &b){
to[++cnt]=v; val[cnt][]=a; val[cnt][]=b; nxt[cnt]=h[u]; h[u]=cnt;
} void dfs1(int x,int fa){
dfn[x]=++tim;
For(i,x) if ((k=to[i])!=fa){
if (!dfn[k]) dfs1(k,x),sz[x]+=sz[k];
else if (dfn[k]<dfn[x]) du[++tot]=x,dv[tot]=k,mark[x]=mark[k]=;
}
mark[x]|=(sz[x]>=); if (mark[x]) sz[x]=;
} void dfs3(int x){
dp[x][]=ban[x][] ? : g[x][];
dp[x][]=ban[x][] ? : g[x][];
For(i,x){
dfs3(k=to[i]);
dp[x][]=1ll*dp[x][]*(1ll*val[i][].k0*dp[k][]%mod+1ll*val[i][].k1*dp[k][]%mod)%mod;
dp[x][]=1ll*dp[x][]*(1ll*val[i][].k0*dp[k][]%mod+1ll*val[i][].k1*dp[k][]%mod)%mod;
}
}
}G1,G2; int dfs2(int x){
g[x][]=g[x][]=; vis[x]=; int t=;
for (int i=G1.h[x],k; i; i=G1.nxt[i]) if (!vis[k=G1.to[i]]){
int z=dfs2(k);
if (!z) g[x][]=1ll*g[x][]*(g[k][]+g[k][])%mod,g[x][]=1ll*g[x][]*g[k][]%mod;
else{
if (mark[x]) G2.add(x,z,K[k][]+K[k][],K[k][]);
else K[x][]=K[k][]+K[k][],K[x][]=K[k][],t=z;
}
}
if (mark[x]) K[x][]=(P){,},K[x][]=(P){,},t=x;
else K[x][]=K[x][]*g[x][],K[x][]=K[x][]*g[x][];
return t;
} int main(){
freopen("bzoj5287.in","r",stdin);
freopen("bzoj5287.out","w",stdout);
scanf("%d%d",&n,&m);
rep(i,,m) scanf("%d%d",&u,&v),G1.add(u,v),G1.add(v,u);
G1.dfs1(,); mark[]=; dfs2();
for (int S=; S<(<<tot); S++){
rep(i,,tot) if (S&(<<(i-))) ban[dv[i]][]=,ban[du[i]][]=; else ban[dv[i]][]=;
G2.dfs3(); ans=(ans+(dp[][]+dp[][])%mod)%mod;
rep(i,,tot) if (S&(<<(i-))) ban[dv[i]][]=,ban[du[i]][]=; else ban[dv[i]][]=;
}
printf("%d\n",ans);
return ;
}

[BZOJ5287][HNOI2018]毒瘤(虚树DP)的更多相关文章

  1. BZOJ.5287.[AHOI HNOI2018]毒瘤(虚树 树形DP)

    BZOJ LOJ 洛谷 设\(f[i][0/1]\)表示到第\(i\)个点,不选/选这个点的方案数.对于一棵树,有:\[f[x][0]=\prod_{v\in son[x]}(f[v][0]+f[v] ...

  2. bzoj 3572世界树 虚树+dp

    题目大意: 给一棵树,每次给出一些关键点,对于树上每个点,被离它最近的关键点(距离相同被标号最小的)控制 求每个关键点控制多少个点 分析: 虚树+dp dp过程如下: 第一次dp,递归求出每个点子树中 ...

  3. bzoj 2286 [Sdoi2011]消耗战 虚树+dp

    题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ...

  4. 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP

    [题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...

  5. [BZOJ2286][SDOI2011]消耗战(虚树DP)

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4998  Solved: 1867[Submit][Statu ...

  6. BZOJ 3572 [HNOI2014]世界树 (虚树+DP)

    题面:BZOJ传送门 洛谷传送门 题目大意:略 细节贼多的虚树$DP$ 先考虑只有一次询问的情况 一个节点$x$可能被它子树内的一个到x距离最小的特殊点管辖,还可能被管辖fa[x]的特殊点管辖 跑两次 ...

  7. 洛谷P2495 [SDOI2011]消耗战(虚树dp)

    P2495 [SDOI2011]消耗战 题目链接 题解: 虚树\(dp\)入门题吧.虚树的核心思想其实就是每次只保留关键点,因为关键点的dfs序的相对大小顺序和原来的树中结点dfs序的相对大小顺序都是 ...

  8. BZOJ5287 HNOI2018毒瘤(虚树+树形dp)

    显然的做法是暴力枚举非树边所连接两点的选或不选,大力dp.考场上写的是最暴力的O(3n-mn),成功比大众分少10分.容斥或者注意到某些枚举是不必要的就能让底数变成2.但暴力的极限也就到此为止. 每次 ...

  9. 洛谷 P4426 - [HNOI/AHOI2018]毒瘤(虚树+dp)

    题面传送门 神仙虚树题. 首先考虑最 trival 的情况:\(m=n-1\),也就是一棵树的情况.这个我相信刚学树形 \(dp\) 的都能够秒掉罢(确信).直接设 \(dp_{i,0/1}\) 在表 ...

随机推荐

  1. 调整扩大VMDK格式VirtualBox磁盘空间

    如果虚拟机的格式是VDI格式的, 那么可以通过这篇文章来调整磁盘大小: 调整Virtual Box硬盘大小 不过楼主当初在创建虚拟机的时候,是用的VMDK格式, 以求与VMWare的兼容性.这时候要扩 ...

  2. JS设计模式——7.工厂模式(示例-RSS阅读器)

    RSS阅读器 由于我们只想跟RSS容器对象打交道,所以用一个工厂来实例化这些内部对象并把它们组装到一个RSS阅读器中. 使用工厂方法在好处在于,我们创建的RSS阅读器类不会与那些成员对象紧密耦合在一起 ...

  3. Servlet笔记6--Servlet程序改进

    第一步改进,GenericServlet: 我们目前所有放入Servlet类直接实现了javax.servlet.Servlet接口,但是这个接口中有很多方法是目前不需要的,我们可能只需要编写serv ...

  4. 连接数据库及出现System.AccessViolationException错误的解决方法

    调试后发现, connection.Open();以后报错,System.AccessViolationException: 尝试读取或写入受保护的内存.这通常指示其他内存已损坏,网上搜了很多都没有作 ...

  5. 谈谈Linux内核驱动的coding style【转】

    转自:http://www.cnblogs.com/wwang/archive/2011/02/24/1960283.html 最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离 ...

  6. Task多线程进行多进程

    using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using Sys ...

  7. [转载]Windows服务编写原理及探讨(3)

    (三)对服务的深入讨论之下 现在我们还剩下一个函数可以在细节上讨论,那就是服务的CtrlHandler函数. 当调用RegisterServiceCtrlHandler函数时,SCM得到并保存这个回调 ...

  8. 按需引入antd报错问题

    1.使用create-react-app工具创建了一个项目 create-react-app antd-demo 2.安装babel-plugin-import npm install babel-p ...

  9. asterisk各种报错

    1.控制台打印出: Got SIP response "Temporarily Unavailable" back from 210.13.87.110:5060   造成原因:在 ...

  10. 读书笔记--C陷阱与缺陷(四)

    第四章 1. 连接器 C语言的一个重要思想就是分别编译:若干个源程序可在不同的时候单独进行编译,恰当的时候整合到一起. 连接器一般与C编译器分离,其输入是一组目标模块(编译后的模块)和库文件,输出是一 ...