自己 yy 了一个动态 dp 做法,应该是全网唯一用 LCT 写的.

code:

#include <bits/stdc++.h>
#define ll long long
#define lson tr[x].ch[0]
#define rson tr[x].ch[1]
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
const int N=200005;
const ll mod=998244353;
vector<int>EDGE;
int edges=1,n,m,F[N][2];
int hd[N],to[N<<1],nex[N<<1],from[N<<1],mark[N<<1],vis[N],sta[N];
int qpow(int x,int y)
{
int tmp=1;
while(y)
{
if(y&1) tmp=1ll*tmp*x%mod;
x=1ll*x*x%mod, y>>=1;
}
return tmp;
}
int INV(int x) { return qpow(x,mod-2); }
void add(int u,int v)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,from[edges]=u;
}
void dfs(int u,int ff)
{
vis[u]=1;
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==ff||mark[i]) continue;
if(vis[v])
{
mark[i]=mark[i^1]=1, EDGE.push_back(i);
continue;
}
dfs(v,u);
}
}
struct Num
{
int val,cnt;
Num() { val=cnt=0; }
void ins(int a)
{
val=a,cnt=0;
if(!val) val=1,cnt=1;
}
Num operator*(Num b) const
{
Num re;
re.val=1ll*val*b.val%mod;
re.cnt=cnt+b.cnt;
return re;
}
Num operator/(Num b) const
{
Num re;
re.cnt=cnt-b.cnt;
re.val=1ll*val*INV(b.val)%mod;
return re;
}
int get() { return cnt?0:val; }
}tmp[N][2][2];
struct matrix
{
int a[2][2];
matrix() { memset(a,0,sizeof(a)); }
void I()
{
a[0][0]=a[1][1]=1;
a[0][1]=a[1][0]=0;
}
int *operator[](int x) { return a[x]; }
}t[N],po[N];
matrix operator*(matrix a,matrix b)
{
matrix c;
for(int i=0;i<2;++i)
{
for(int j=0;j<2;++j)
for(int k=0;k<2;++k)
c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j]%mod)%mod;
}
return c;
}
void cop(int x)
{
for(int i=0;i<2;++i)
{
for(int j=0;j<2;++j)
t[x][i][j]=tmp[x][i][j].get();
}
}
struct node
{
int ch[2],f,rev;
}tr[N];
int get(int x)
{
return tr[tr[x].f].ch[1]==x;
}
int isrt(int x)
{
return !(tr[tr[x].f].ch[0]==x||tr[tr[x].f].ch[1]==x);
}
void pushup(int x)
{
cop(x);
t[x]=po[x]*t[x];
if(lson) t[x]=t[lson]*t[x];
if(rson) t[x]=t[x]*t[rson];
}
void rotate(int x)
{
int old=tr[x].f,fold=tr[old].f,which=get(x);
if(!isrt(old)) tr[fold].ch[tr[fold].ch[1]==old]=x;
tr[old].ch[which]=tr[x].ch[which^1],tr[tr[old].ch[which]].f=old;
tr[x].ch[which^1]=old,tr[old].f=x,tr[x].f=fold;
pushup(old),pushup(x);
}
void splay(int x)
{
int u=x,v=0,fa;
for(sta[++v]=u;!isrt(u);u=tr[u].f) sta[++v]=tr[u].f;
for(u=tr[u].f;(fa=tr[x].f)!=u;rotate(x))
{
if(tr[fa].f!=u)
{
rotate(get(fa)==get(x)?fa:x);
}
}
}
void Access(int x)
{
for(int y=0;x;y=x,x=tr[x].f)
{
splay(x);
if(rson)
{
Num a,b;
a.ins(t[rson][0][0]);
b.ins(t[rson][0][0]+t[rson][1][0]);
tmp[x][1][0]=tmp[x][1][0]*a;
tmp[x][0][0]=tmp[x][0][0]*b;
tmp[x][0][1]=tmp[x][0][1]*b;
}
if(y)
{
Num a,b;
a.ins(t[y][0][0]);
b.ins(t[y][0][0]+t[y][1][0]);
tmp[x][1][0]=tmp[x][1][0]/a;
tmp[x][0][0]=tmp[x][0][0]/b;
tmp[x][0][1]=tmp[x][0][1]/b;
}
rson=y;
pushup(x);
}
}
void prepare(int u,int ff)
{
po[u].I();
tr[u].f=ff;
tmp[u][1][1].ins(0);
tmp[u][0][0].ins(1);
tmp[u][0][1].ins(1);
tmp[u][1][0].ins(1);
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==ff||mark[i]) continue;
prepare(v,u);
Num a,b;
a.ins(tmp[v][0][0].get());
b.ins(tmp[v][0][0].get()+tmp[v][1][0].get());
tmp[u][0][0]=tmp[u][0][0]*b;
tmp[u][0][1]=tmp[u][0][1]*b;
tmp[u][1][0]=tmp[u][1][0]*a;
}
pushup(u);
}
int main()
{
int i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs(1,0);
prepare(1,0);
ll ans=0ll;
int sta=EDGE.size();
if(sta==0)
{
Access(3),splay(3);
ans=(t[3][0][0]+t[3][1][0])%mod;
}
else
{
for(i=0;i<(1<<sta);++i)
{
for(j=0;j<sta;++j)
{
if(i&(1<<j))
{
int u=from[EDGE[j]];
int v=to[EDGE[j]];
Access(u),splay(u);
po[u][0][0]=0;
pushup(u); Access(v),splay(v);
po[v][1][1]=0;
pushup(v);
}
else
{
int u=from[EDGE[j]];
Access(u),splay(u);
po[u][1][1]=0;
pushup(u);
}
}
Access(1),splay(1);
(ans+=(t[1][0][0]+t[1][1][0])%mod)%=mod;
for(j=0;j<sta;++j)
{
if(i&(1<<j))
{
int u=from[EDGE[j]];
int v=to[EDGE[j]];
Access(u),splay(u);
po[u][0][0]=1;
pushup(u);
Access(v),splay(v);
po[v][1][1]=1;
pushup(v);
}
else
{
int u=from[EDGE[j]];
Access(u),splay(u);
po[u][1][1]=1;
pushup(u);
}
}
}
}
printf("%lld\n",ans);
return 0;
}

  

BZOJ 5287: [Hnoi2018]毒瘤 动态dp(LCT+矩阵乘法)的更多相关文章

  1. BZOJ 4712 洪水 动态dp(LCT+矩阵乘法)

    把之前写的版本改了一下,这个版本的更好理解一些. 特地在一个链的最底端特判了一下. code: #include <bits/stdc++.h> #define N 200005 #def ...

  2. bzoj 5287: [Hnoi2018]毒瘤

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

  3. 【loj2325】「清华集训 2017」小Y和恐怖的奴隶主 概率dp+倍增+矩阵乘法

    题目描述 你有一个m点生命值的奴隶主,奴隶主受伤未死且当前随从数目不超过k则再召唤一个m点生命值的奴隶主. T次询问,每次询问如果如果对面下出一个n点攻击力的克苏恩,你的英雄期望会受到到多少伤害. 输 ...

  4. bzoj 1009 [HNOI2008]GT考试(DP+KMP+矩阵乘法)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1009 [题意] 给定一个字符串T,问长度为n且不包含串T的字符串有多少种. [思路] ...

  5. BZOJ 1444 [JSOI2009]有趣的游戏 (AC自动机、概率与期望DP、矩阵乘法)

    诶这题洛谷居然没有??? 题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1444 题解: 我见到主要有三种做法. 一是矩阵乘法.设\(d ...

  6. 【BZOJ2510】弱题 期望DP+循环矩阵乘法

    [BZOJ2510]弱题 Description 有M个球,一开始每个球均有一个初始标号,标号范围为1-N且为整数,标号为i的球有ai个,并保证Σai = M. 每次操作等概率取出一个球(即取出每个球 ...

  7. [HNOI2008]GT考试(kmp,dp,矩阵乘法)

    [HNOI2008]GT考试(luogu) Description 求有多少个n位的数字串不包含m位的字符串(范围 n <= 1e9 n<=1e9, m <= 20m<=20) ...

  8. BZOJ 1009 HNOI2008 GT考试 KMP算法+矩阵乘法

    标题效果:给定的长度m数字字符串s.求不包括子s长度n数字串的数目 n<=10^9 看这个O(n)它与 我们不认为这 令f[i][j]长度i号码的最后的字符串j位和s前者j数字匹配方案 例如,当 ...

  9. BZOJ 1875: [SDOI2009]HH去散步(矩阵乘法)

    首先,题意就把我们引向了矩阵乘法,注意边长m<=60,那么就按边建图,变成一个120个点的图,然后乱搞就行了。 PS:WA了N久改了3次终于A了QAQ CODE: #include<cst ...

随机推荐

  1. C# IEnumerable接口

    问: 集合很好用,而且非常简单,但是我不明白 为什么数组.ArrayList 和 Hasttable 这些集合都能用foreach直接遍历呢?我想自己定义一个集合类,应该怎么做呢? 回答:这个问题问的 ...

  2. 阿里巴巴 Java 开发手册(一):命名风格

    命名风格 1. [强制] 代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束. 反例: _name / __name / $Object / name_ / name$ / Obj ...

  3. 浅谈分词算法基于字的分词方法(HMM)

    前言 在浅谈分词算法(1)分词中的基本问题我们讨论过基于词典的分词和基于字的分词两大类,在浅谈分词算法(2)基于词典的分词方法文中我们利用n-gram实现了基于词典的分词方法.在(1)中,我们也讨论了 ...

  4. Python进阶----网络通信基础 ,OSI七层协议() ,UDP和TCP的区别 , TCP/IP协议(三次握手,四次挥手)

    Python进阶----网络通信基础 ,OSI七层协议() ,UDP和TCP的区别 , TCP/IP协议(三次握手,四次挥手) 一丶CS/BS 架构 C/S: 客户端/服务器    定义:       ...

  5. aria config

    aria2c --conf-path=aria2.conf mine: max-concurrent-downloads=5 continue=true max-overall-download-li ...

  6. k8s--complete-demo.yaml

  7. Java知识回顾 (12) package

    本资料来自于runoob,略有修改. 为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间. Java 使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(cl ...

  8. 如何解决div背景色半透明,里面的图片不透明问题

    用rgba可以实现,不能用opacity 背景做成透明的背景图,opacity属性影响子集的,除非把两者独立开~

  9. 2. ES6基础-let和const命令

    目录 1. let命令 1.1 用法 1. 2 不存在变量提升 1.3 区域绑定 1.4 不允许重复声明 2. const命令 2.1 用法 2.2 与let类似的特性 2.3 const本质 2.4 ...

  10. security Alternative forms secuerity

    security Alternative forms secuerity (mostly obsolete) English Alternative forms secuerity Pronuncia ...