自己 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. 快速排序(Quick Sort)C语言

    已知数组 src 如下: [5, 3, 7, 6, 4, 1, 0, 2, 9, 10, 8] 快速排序1 在数组 src[low, high] 中,取 src[low] 作为 关键字(key) . ...

  2. JS Web API 拖拽对话框案例

    <style> .login-header { width: 100%; text-align: right; height: 30px; font-size: 24px; line-he ...

  3. docker-compose up 启动容器服务超时错误:ERROR: An HTTP request took too long to complete. Retry with --verbose to obtain debug information.

    问题: 本人正在使用docker运行一个中型的项目,包含40多个微服务及相关的docker.由于docker-compose up 同时启动的服务过多,超过了请求HTTP限制的60s时间仍未全部成功启 ...

  4. Jenkins+harbor+gitlab+k8s 部署maven项目

    一.概述 maven项目部署流程图如下: 环境介绍 操作系统 ip 角色 版本 ubuntu-16.04.4-server-amd64 192.168.10.122 Jenkins+harbor Je ...

  5. zbar android sdk源码编译

    zbar,解析条码和二维码的又一利器,zbar代码是用c语言编写的,如果想在Android下使用zbar类库,就需要使用NDK将zbar编译成.so加载使用,zbar编译好的Android SDK可以 ...

  6. Eclipse创建ssm项目

    1.创建Maven项目 2.勾选上面的 3.打成war包的形式 4.配置webapp.xml  Project Facets——Dynamic Wed Module 2.5 ——然后点击下面的提示 5 ...

  7. 【i.MX6UL/i.MX6ULL开发常见问题】单独编译内核,uboot生成很多文件,具体用哪一个?

    [i.MX6UL/i.MX6ULL开发常见问题]2.3单独编译内核,uboot生成很多文件,具体用哪一个? 答:内核编译出来的文件是~/MYiR-imx-Linux/arch/arm/boot/目录下 ...

  8. 【转载】华为荣耀V9手机如何设置WiFi热点共享

    有时候我们在电脑的时候发现没有无线网络以及有线网络,如果你的手机有相应网络,并且流量足够(当前很多手机流量套餐都是不限量了),可以开启手机上的Wifi热点进行流量共享使用,开启Wifi流量热点后,电脑 ...

  9. appium 操作界面

    操作界面函数: 1.swipe():模拟滑动 2.tap():点击坐标 1.swipe()函数:用来模拟滑动操作 参数说明: 坐标就是x/y坐标 duration是滑动从起点到终点坐标所耗费的时间. ...

  10. JSP内置对象(下)

    session的生命周期 创建 活动 销毁 application对象 Page对象