虚树+dp

直接看zlttttt的强大题解 zlttttt的题解看这里

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100000+10,MAXM=100010+10,Mod=998244353;
int n,m,e,to[MAXM<<1],nex[MAXM<<1],beg[MAXN],w[MAXM<<1],Jie[MAXN][20],dfn,dfsrk[MAXN],st[MAXN],ed[MAXN],dep[MAXN],cnt,Idfn,Icnt,Istack[MAXN],Ist[MAXN],Idfsrk[MAXN],slt[MAXN],Ipoint[MAXN],In,Ie,Ibeg[MAXN],Inex[MAXM<<1],Ito[MAXM<<1],f[MAXN][2],lmt[MAXN],g[MAXN][2];
std::pair<int,int> stack[MAXM];
struct data{
int k0,k1;
data(int a=0,int b=0){
k0=a,k1=b;
}
inline data operator + (const data &A) const {
return data(k0+A.k0,k1+A.k1);
};
inline data operator * (const int a) const {
return data(1ll*k0*a%Mod,1ll*k1*a%Mod);
};
inline int value(int a,int b){
return (1ll*a*k0%Mod+1ll*b*k1%Mod)%Mod;
};
};
data coeffi[MAXN][2];
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y)
{
to[++e]=y;
nex[e]=beg[x];
beg[x]=e;
w[e]=1;
}
inline void dfs1(int x,int f)
{
dep[x]=dep[f]+1;Jie[x][0]=f;
dfsrk[st[x]=++dfn]=x;
for(register int i=beg[x];i;i=nex[i])
if(to[i]==f)w[i]=0;
else
{
if(!dep[to[i]])dfs1(to[i],x);
else w[i]=0,stack[++cnt]=std::pair<int,int>(min(x,to[i]),max(x,to[i]));
}
ed[x]=dfn;
}
inline bool cmp(int a,int b)
{
return st[a]<st[b];
}
inline int LCA(int u,int v)
{
if(dep[u]<dep[v])std::swap(u,v);
if(dep[u]>dep[v])
for(register int i=19;i>=0;--i)
if(dep[Jie[u][i]]>=dep[v])u=Jie[u][i];
if(u==v)return u;
for(register int i=19;i>=0;--i)
if(Jie[u][i]!=Jie[v][i])u=Jie[u][i],v=Jie[v][i];
return Jie[u][0];
}
inline void Iinsert(int x,int y)
{
Ito[++Ie]=y;
Inex[Ie]=Ibeg[x];
Ibeg[x]=Ie;
}
inline void dfs3(int x,int tp)
{
f[x][0]=f[x][1]=1;
for(register int i=beg[x];i;i=nex[i])
if(to[i]!=Jie[x][0]&&to[i]!=tp&&!slt[to[i]])
{
dfs3(to[i],tp);
f[x][0]=1ll*f[x][0]*((f[to[i]][0]+f[to[i]][1])%Mod)%Mod;
f[x][1]=1ll*f[x][1]*f[to[i]][0]%Mod;
}
}
inline void calc(int s,int t)
{
coeffi[s][0]=data(1,0);coeffi[s][1]=data(0,1);
data now;
for(register int i=s;Jie[i][0]!=t;i=Jie[i][0])
{
dfs3(Jie[i][0],i);
slt[Jie[i][0]]=1;
now=coeffi[s][0];
coeffi[s][0]=(coeffi[s][0]+coeffi[s][1])*f[Jie[i][0]][0];
coeffi[s][1]=now*f[Jie[i][0]][1];
}
}
inline void dfs2(int x)
{
for(register int i=Ibeg[x];i;i=Inex[i])dfs2(Ito[i]),calc(Ito[i],x);
f[x][0]=f[x][1]=1;
for(register int i=beg[x];i;i=nex[i])
if(!slt[to[i]]&&to[i]!=Jie[x][0]&&w[i]>0)
{
dfs3(to[i],0);
f[x][0]=1ll*f[x][0]*((f[to[i]][0]+f[to[i]][1])%Mod)%Mod;
f[x][1]=1ll*f[x][1]*f[to[i]][0]%Mod;
}
}
inline void dfs4(int x)
{
g[x][0]=f[x][0];
g[x][1]=f[x][1];
for(register int i=Ibeg[x],k0,k1;i;i=Inex[i])
{
dfs4(Ito[i]);
k0=coeffi[Ito[i]][0].value(g[Ito[i]][0],g[Ito[i]][1]);
k1=coeffi[Ito[i]][1].value(g[Ito[i]][0],g[Ito[i]][1]);
g[x][0]=1ll*g[x][0]*((k0+k1)%Mod)%Mod;
g[x][1]=1ll*g[x][1]*k0%Mod;
}
if(~lmt[x])g[x][lmt[x]^1]=0;
}
int main()
{
freopen("duliu.in","r",stdin);
freopen("duliu.out","w",stdout);
read(n);read(m);
for(register int i=1;i<=m;++i)
{
int u,v;
read(u);read(v);
insert(u,v);insert(v,u);
}
dep[1]=1;
dfs1(1,0);
for(register int j=1;j<20;++j)
for(register int i=1;i<=n;++i)Jie[i][j]=Jie[Jie[i][j-1]][j-1];
std::sort(stack+1,stack+cnt+1);
cnt=std::unique(stack+1,stack+cnt+1)-stack-1;
for(register int i=1;i<=cnt;++i)
{
if(!slt[stack[i].first])
{
slt[stack[i].first]=1;
Ipoint[++In]=stack[i].first;
Ist[Idfsrk[++Idfn]=stack[i].first]=Idfn;
}
if(!slt[stack[i].second])
{
slt[stack[i].second]=1;
Ipoint[++In]=stack[i].second;
Ist[Idfsrk[++Idfn]=stack[i].second]=Idfn;
}
}
std::sort(Ipoint+1,Ipoint+In+1,cmp);
for(register int i=2,limit=In;i<=limit;++i)Ipoint[++In]=LCA(Ipoint[i-1],Ipoint[i]);
Ipoint[++In]=1;
std::sort(Ipoint+1,Ipoint+In+1,cmp);
In=std::unique(Ipoint+1,Ipoint+In+1)-Ipoint-1;
Istack[++Icnt]=Ipoint[1];
for(register int i=2;i<=In;++i)
if(Icnt)
{
while(Icnt&&ed[Istack[Icnt]]<st[Ipoint[i]])Icnt--;
Iinsert(Istack[Icnt],Ipoint[i]);
Istack[++Icnt]=Ipoint[i];
}
for(register int i=1;i<=In;++i)slt[Ipoint[i]]=1;
dfs2(1);
for(register int i=1;i<=n;++i)lmt[i]=-1;
int ans=0;
for(register int i=(1<<Idfn)-1;i>=0;--i)
{
int mark=0;
for(register int j=1;j<=cnt;++j)
if((i>>(Ist[stack[j].first]-1)&1)&&(i>>(Ist[stack[j].second]-1)&1))
{
mark=1;
break;
}
if(mark)continue;
for(register int j=1;j<=Idfn;++j)lmt[Idfsrk[j]]=(i>>(j-1))&1;
dfs4(1);
(ans+=(g[1][0]+g[1][1])%Mod)%=Mod;
}
write(ans,'\n');
return 0;
}

【比赛】HNOI2018 毒瘤的更多相关文章

  1. 【BZOJ5287】[HNOI2018]毒瘤(动态规划,容斥)

    [BZOJ5287][HNOI2018]毒瘤(动态规划,容斥) 题面 BZOJ 洛谷 题解 考场上想到的暴力做法是容斥: 因为\(m-n\le 10\),所以最多会多出来\(11\)条非树边. 如果就 ...

  2. [bzoj5287] [HNOI2018]毒瘤

    题目描述 从前有一名毒瘤. 毒瘤最近发现了量产毒瘤题的奥秘.考虑如下类型的数据结构题:给出一个数组,要求支持若干种奇奇怪怪的修改操作(比如区间加一个数,或者区间开平方),并支持询问区间和.毒瘤考虑了n ...

  3. [HNOI2018]毒瘤

    Description 从前有一名毒瘤. 毒瘤最近发现了量产毒瘤题的奥秘.考虑如下类型的数据结构题:给出一个数组,要求支持若干种奇奇怪怪的修改操作(比如区间加一个数,或者区间开平方),并支持询问区间和 ...

  4. bzoj 5287: [Hnoi2018]毒瘤

    Description Solution \(dfs\) 出一棵生成树之后,多出来的边就都是反祖边了 把反祖边两个端点都拿出来,就会得到最多 \(k=2*(m-n+1)\) 个关键点 除了关键点以外的 ...

  5. 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] ...

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

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

  7. HNOI2018毒瘤

    题面链接 luogu sol 这篇博是骗访问量的QwQ. 考虑树怎么做,简单容斥.诸如\(f[u][0]=\prod (f[v][0]+f[v][1]),f[u][1]=\prod f[v][0]\) ...

  8. [BZOJ5287][HNOI2018]毒瘤(虚树DP)

    暴力枚举非树边取值做DP可得75. 注意到每次枚举出一个容斥状态的时候,都要做大量重复操作. 建立虚树,预处理出虚树上两点间的转移系数.也可动态DP解决. 树上倍增.动态DP.虚树DP似乎是这种问题的 ...

  9. BZOJ 5287: [Hnoi2018]毒瘤 动态dp(LCT+矩阵乘法)

    自己 yy 了一个动态 dp 做法,应该是全网唯一用 LCT 写的. code: #include <bits/stdc++.h> #define ll long long #define ...

随机推荐

  1. HBase第二章 基本API

    1.pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www ...

  2. Vue.js之常用指令

    vue常用指令 vue.js官方给自己的定义是数据模板引擎,并给出了一套渲染数据的指令.本文详细介绍vue.js的常用指令. 官网:点我 一.v-text.v-html v-text:用于绑定文本 v ...

  3. CentOS 7.2二进制安装mysql-5.7.19

    官方文档地址:https://dev.mysql.com/doc/refman/5.7/en/binary-installation.html 开始安装 1.下载mysql二进制包 # cd /usr ...

  4. Egret入门(二)--windows下环境搭建

    准备材料 安装Node.js TypeScript编辑器 HTTP服务器(可选) Chorme(可选) Egret 安装Node.js 打开www.nodejs.org 下载安装(全部next,全默认 ...

  5. jquery on函数和prop与attr区别

    一.jquery on()方法 1.语法 2.例子 $(document).ready(function(){ $("p").on("click",functi ...

  6. NUMA 体系架构

    NUMA 体系架构 SMP 体系架构 NUMA 体系架构 NUMA 结构基本概念 Openstack flavor NUMA 策略 Nova 实现 NUMA 流程 1. SMP 体系架构 CPU 计算 ...

  7. linux云主机小技巧

    微信服务器安装 安装库 python 3.5环境下 pip安装web.py时 会报错 "no module named "utils" 等问题 更换命令为“pip ins ...

  8. python实现中文验证码识别方法(亲测通过)

    验证码截图如下: # coding:utf-8from PIL import Image,ImageEnhanceimport pytesseract#上面都是导包,只需要下面这一行就能实现图片文字识 ...

  9. ARP 攻击

    场景 A攻击者 192.168.1.3 00:00:00:00:00:01 B受害者 192.168.1.2 00:00:00:00:00:02 C路由器 192.168.1.1 00:00:00:0 ...

  10. 周总结<1>

    由于都不清楚周总结的格式,所以就没有写了.不过,上次听了老师的课,觉得应该要好好写写了,至少今后可以明白自己有做过什么事情,至少不会觉得自己在各个方面没有收获.不过,可能没有按照格式来写.希望老师体谅 ...