虚树+树形DP--luoguP4426 [HNOI/AHOI2018]毒瘤

2024-01-03 13:58

本文主要是介绍虚树+树形DP--luoguP4426 [HNOI/AHOI2018]毒瘤,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

传送门

虚树毒瘤题

首先注意到 m m m只比 n n n 10 10 10,所以可以随便找个生成树,把 m m m多出来的边上的点都拎出来建一个虚树,可以枚举每条边的深度较浅的那个点选不选,在虚树上树形 d p dp dp,然后发现虚树上父亲到儿子的系数是不变的,所以可以树形 d p dp dp预处理出来

k [ u ] [ 0 / 1 ] [ 0 / 1 ] k[u][0/1][0/1] k[u][0/1][0/1]表示 u u u f a u fa_u fau f a u fa_u fau选或不选, u u u选或不选的系数,然后每次枚举之后再虚树上预处理就好

细节非常多

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define N 100005
#define LL long long
using namespace std;
const int mod=998244353;template<class T>inline void rd(T &x){x=0; short f=1; char c=getchar();while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();x*=f;
}int n,m,cnt,head[N],nxt[N<<1],to[N<<1],ecnt,dep[N],f[N][20];
int stk[N],top,dfn[N],siz[N],fat[N],a[N],tot,num;
int ed,dp[N][2],k[N][2][2],cho[N],g[N][2],ans;
bool vis[N];
vector<int> vec[N];struct EDGE{int fr,to;}edge[15];inline int find(int x){return x==fat[x]?x:(fat[x]=find(fat[x]));}
inline bool cmp(int x,int y){return dfn[x]<dfn[y];}inline void add(int x,int y){to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;to[++cnt]=x,nxt[cnt]=head[y],head[y]=cnt;
}
inline void add1(int x,int y){vec[x].push_back(y);}void dfs(int u,int fa){siz[u]=1; dfn[u]=++num;for(int i=head[u],v;i;i=nxt[i])if((v=to[i])!=fa){dep[v]=dep[u]+1; f[v][0]=u;for(int j=1;j<=17;j++)f[v][j]=f[f[v][j-1]][j-1];dfs(v,u);siz[u]+=siz[v];}
}inline int LCA(int x,int y){if(dep[x]<dep[y]) swap(x,y);for(int i=17;i>=0;i--)if(dep[f[x][i]]>=dep[y]) x=f[x][i];if(x==y) return x;for(int i=17;i>=0;i--)if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];return f[x][0];
}void DP_tot(int u,int ban){dp[u][0]=dp[u][1]=1;for(int i=head[u],v;i;i=nxt[i])if((v=to[i])!=f[u][0] && v!=ban && !vis[v]){DP_tot(v,ban);dp[u][0]=1LL*dp[u][0]*((dp[v][0]+dp[v][1])%mod)%mod;dp[u][1]=1LL*dp[u][1]*dp[v][0]%mod;}
}inline void work(int x,int y){k[y][0][0]=1,k[y][1][1]=1;for(int i=y;f[i][0]!=x;i=f[i][0]){DP_tot(f[i][0],i); vis[f[i][0]]=1;int tmp0=k[y][0][0],tmp1=k[y][0][1];k[y][0][0]=1LL*dp[f[i][0]][0]*(k[y][0][0]+k[y][1][0])%mod;k[y][0][1]=1LL*dp[f[i][0]][0]*(k[y][0][1]+k[y][1][1])%mod;k[y][1][0]=1LL*dp[f[i][0]][1]*tmp0%mod;k[y][1][1]=1LL*dp[f[i][0]][1]*tmp1%mod;}
}inline void build(){int x,y,z;sort(a+1,a+tot+1,cmp);num=tot; ed=1<<ecnt;for(int i=2;i<=num;i++){x=a[i-1],y=a[i];z=LCA(x,y);if(!vis[z]) a[++tot]=z,vis[z]=1;}if(!vis[1]) a[++tot]=1,vis[1]=1;sort(a+1,a+tot+1,cmp); stk[++top]=a[1];for(int i=2;i<=tot;i++){while(top && dfn[stk[top]]+siz[stk[top]]<=dfn[a[i]]) top--;add1(stk[top],a[i]); stk[++top]=a[i];}
}void dfs_pre(int u){for(int i=0;i<vec[u].size();i++){dfs_pre(vec[u][i]);work(u,vec[u][i]);}dp[u][0]=dp[u][1]=1;for(int i=head[u],v;i;i=nxt[i])if((v=to[i])!=f[u][0] && !vis[v]){DP_tot(v,0);dp[u][0]=1LL*dp[u][0]*((dp[v][0]+dp[v][1])%mod)%mod;dp[u][1]=1LL*dp[u][1]*dp[v][0]%mod;}
}void DP(int u){g[u][1]=dp[u][1],g[u][0]=dp[u][0];for(int i=0,v;i<vec[u].size();i++){v=vec[u][i];DP(v);int k0=(1LL*k[v][0][0]*g[v][0]%mod+1LL*k[v][0][1]*g[v][1]%mod)%mod;int k1=(1LL*k[v][1][0]*g[v][0]%mod+1LL*k[v][1][1]*g[v][1]%mod)%mod;g[u][0]=1LL*g[u][0]*((k0+k1)%mod)%mod;g[u][1]=1LL*g[u][1]*k0%mod;}if(~cho[u]) g[u][cho[u]^1]=0;
}inline void solve(){for(int j=1;j<=ecnt;j++) if(dfn[edge[j].fr]>dfn[edge[j].to]) swap(edge[j].fr,edge[j].to);for(int i=0;i<ed;i++){memset(cho,-1,sizeof cho);bool flg=true;for(int j=1;j<=ecnt;j++)if((1<<(j-1))&i){if(cho[edge[j].fr]==0 || cho[edge[j].to]==1) {flg=false;break;}cho[edge[j].fr]=1,cho[edge[j].to]=0;}else{if(cho[edge[j].fr]==1) {flg=false;break;}cho[edge[j].fr]=0;}if(!flg) continue; DP(1);(ans+=(g[1][0]+g[1][1])%mod)%=mod;}
}int main(){//freopen("in.in","r",stdin);//freopen("out.out","w",stdout);rd(n),rd(m); int x,y;for(int i=1;i<=n;i++) fat[i]=i;for(int i=1;i<=m;i++){rd(x),rd(y);int fx=find(x),fy=find(y);if(fx!=fy) fat[fx]=fy,add(x,y);else {edge[++ecnt].fr=x,edge[ecnt].to=y;if(!vis[x]) a[++tot]=x,vis[x]=1;if(!vis[y]) a[++tot]=y,vis[y]=1;}}dep[1]=1; dfs(1,0); build(); dfs_pre(1); solve();printf("%d\n",ans);return 0;
}

这篇关于虚树+树形DP--luoguP4426 [HNOI/AHOI2018]毒瘤的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/565920

相关文章

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

uva 10154 DP 叠乌龟

题意: 给你几只乌龟,每只乌龟有自身的重量和力量。 每只乌龟的力量可以承受自身体重和在其上的几只乌龟的体重和内。 问最多能叠放几只乌龟。 解析: 先将乌龟按力量从小到大排列。 然后dp的时候从前往后叠,状态转移方程: dp[i][j] = dp[i - 1][j];if (dp[i - 1][j - 1] != inf && dp[i - 1][j - 1] <= t[i]

uva 10118 dP

题意: 给4列篮子,每次从某一列开始无放回拿蜡烛放入篮子里,并且篮子最多只能放5支蜡烛,数字代表蜡烛的颜色。 当拿出当前颜色的蜡烛在篮子里存在时,猪脚可以把蜡烛带回家。 问最多拿多少只蜡烛。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cs

uva 10069 DP + 大数加法

代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <cl

uva 10029 HASH + DP

题意: 给一个字典,里面有好多单词。单词可以由增加、删除、变换,变成另一个单词,问能变换的最长单词长度。 解析: HASH+dp 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

XTU 1233 n个硬币连续m个正面个数(dp)

题面: Coins Problem Description: Duoxida buys a bottle of MaiDong from a vending machine and the machine give her n coins back. She places them in a line randomly showing head face or tail face o

dp算法练习题【8】

不同二叉搜索树 96. 不同的二叉搜索树 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n = 3输出:5 示例 2: 输入:n = 1输出:1 class Solution {public int numTrees(int n) {int[] dp = new int