自己 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. vuex的Store简单使用过程

    介绍 Store的代码结构一般由State.Getters.Mutation.Actions这四种组成,也可以理解Store是一个容器,Store里面的状态与单纯的全局变量是不一样的,无法直接改变st ...

  2. kafka学习笔记(二)——基础入门

    1.集群规划 从官网下载jar包 http://kafka.apache.org/downloads.html,我选择的是kafka_2.11-0.11.0.0.tgz版本 规划一下集群环境先~ ha ...

  3. C#高效编程

    一. 使用readonly而不是const const是编译时常量,readonly是运行时常量.如果引用了一个库中的const常量,则在更新了程序集,但应用程序没有重新编译时,运行结果会出错 如程序 ...

  4. deppin Linux下安装docker

    首先楼主用的是deppin15.11 docker 简介:Docker作为一个软件集装箱化平台,可以让开发者构建应用程序时,将它与其依赖环境一起打包到一个容器中,然后很容易地发布和应用到任意平台中. ...

  5. sudo apt-get install libstdc++6

    sudo apt-get install libstdc++6 yum install  libncurses.so.5 sudo apt-get install libncurses.so.5 su ...

  6. 一个超实用的python爬虫功能使用 requests BeautifulSoup

    一个简单的数据爬取的示例 import os,re import requests import random import time from bs4 import BeautifulSoup us ...

  7. Privoxy搭建代理服务器

    Privoxy搭建代理服务器 Docker Hub镜像地址 Dockerfile FROM alpine EXPOSE 8118 RUN apk --no-cache --update add pri ...

  8. 【转载】C#中List集合使用LastIndexOf判断元素最后一次出现的索引位置

    在C#的List集合操作中,有时候需要判断元素对象在List集合中第一次出现的索引位置信息,此时需要使用到List集合的IndexOf方法来判断,如果元素存在List集合中,则IndexOf方法返回所 ...

  9. 【GLG Toolkit 行业案例】Baltic Information Systems, Ltd.公司选择使用GLG Toolkit

    BIS (Baltic Information Systems, Ltd.)是一家专门为核电厂开发安全和过程监控系统的软件公司. BIS的新产品 BISMARC 是一个通用过程控制和监控的SCADA系 ...

  10. mysql replace into 实现存在则更新,不存在则插入

    测试用的mysql数据库: 新建测试表: CREATE TABLE `test` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `text` varchar(2 ...