D - Tree Partition

考虑将树转换到一个序列上,钦定\(1\)为根节点,\(1\)的父亲为\(0\),在序列上,孩子向父亲连边

然后考虑设\(dp\)状态\(dp[i][j]\)表示前\(i\)个点,分成\(j\)段的方案数,那么\(dp[i][j]\)从\(dp[k][j-1]\)转移过来要满足以下条件之一:

点\(i\)的后向边\((a,b)\)满足\(a\leq i\),\(b>i\),区间\([i,j]\)的前向边\((a,b)\)满足\(a\in[i,j]\),\(b<i\)

设\(x_1\)表示倒数第二个后向边的起点,\(x_2\)表示倒数第一个后向边的起点

那么对于\(<x_1\)的\(k\)不能转

\([x_1,x_2)\)的\(k\),要满足\([k+1,i]\)没有前向边

\([x_2,i)\)的\(k\),要满足\([k+1,i]\)有且仅有一条前向边

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=2e5+5,MOD=998244353;
int n,k;
int head[N],cnt=1,fa[N],dp[N][405];
struct node{
int nxt,v;
}tree[N<<1];
void add(int u,int v){
tree[++cnt]={head[u],v},head[u]=cnt;
tree[++cnt]={head[v],u},head[v]=cnt;
}
void dfs(int u){
for(int i=head[u],v;i;i=tree[i].nxt){
if(fa[u]==(v=tree[i].v)) continue;
fa[v]=u,dfs(v);
}
}
int ad(int x,int y){
x+=y;
if(x>=MOD) x-=MOD;
if(x<0) x+=MOD;
return x;
}
int c[N],tr[N];
vector<int> sum[2][405],id[2];
set<int> pos;
int suf[N],top;
int main(){
scanf("%d%d",&n,&k),++n,add(1,2);
for(int i=1,u,v;i<n-1;++i) scanf("%d%d",&u,&v),++u,++v,add(u,v);
for(int i=1;i<=n;++i) pos.insert(i);
fa[2]=1,dfs(2);
id[0].pb(0),id[1].pb(0);
for(int i=0;i<=k;++i) sum[0][i].pb(0),sum[1][i].pb(0);
dp[1][0]=1,sum[0][0].pb(1),id[0].pb(1);
for(int i=1;i<=k;++i) sum[0][i].pb(0);
tr[1]=1;
for(int i=2,x1,x2;i<=n;++i){
if(fa[i]>i) suf[++top]=i;
if(fa[i]<i){
if(pos.size()&&(*prev(pos.end()))>=fa[i])
for(auto it=pos.lower_bound(fa[i]);it!=pos.end()&&(*it)<i;){
++c[*it];
if(c[*it]>1){
id[1].pop_back();
for(int j=0;j<=k;++j) sum[1][j].pop_back();
it=pos.erase(it);
}else ++it;
}
if(pos.size()&&(*prev(pos.end()))>=fa[i])
for(auto it=pos.lower_bound(fa[i]);it!=pos.end()&&(*it)<i;++it){
id[0].pop_back(),id[1].pb(*it);
for(int j=0;j<=k;++j) sum[0][j].pop_back(),sum[1][j].pb(ad(sum[1][j].back(),dp[*it][j]));
tr[*it]=sum[1][0].size()-1;
}
}
while(top&&fa[suf[top]]<=i) --top;
if(!top) x1=x2=1;
else{
x2=suf[top--];
while(top&&fa[suf[top]]<=i) --top;
if(top) x1=suf[top]; else x1=1;
suf[++top]=x2;
}
int l1,r1,l2,r2;
if(*(id[0].end()-1)<x1||x1>x2-1) l1=r1=0;
else l1=tr[*lower_bound(id[0].begin(),id[0].end(),x1)],r1=tr[*(upper_bound(id[0].begin(),id[0].end(),x2-1)-1)];
if(*(id[1].end()-1)<x2||x2>i-1) l2=r2=0;
else l2=tr[*lower_bound(id[1].begin(),id[1].end(),x2)],r2=tr[*(upper_bound(id[1].begin(),id[1].end(),i-1)-1)];
for(int j=1;j<=k;++j){
dp[i][j]=ad(ad(sum[0][j-1][r1],-sum[0][j-1][max(0,l1-1)]),ad(sum[1][j-1][r2],-sum[1][j-1][max(0,l2-1)]));
sum[0][j].pb(ad(sum[0][j].back(),dp[i][j]));
// if(j<=i-1) cout<<i<<" "<<j<<" "<<dp[i][j]<<"----\n"<<x1<<" "<<x2<<" "<<l1<<" "<<r1<<" "<<l2<<" "<<r2<<"\n"<<ad(sum[0][j-1][r1],-sum[0][j-1][max(0,l1-1)])<<" "<<ad(sum[1][j-1][r2],-sum[1][j-1][max(0,l2-1)])<<endl;
}
sum[0][0].pb(sum[0][0].back()),id[0].pb(i),tr[i]=sum[0][0].size()-1;
}
for(int i=1;i<=k;++i) printf("%d\n",dp[n][i]); return 0;

[gym103860D]Tree Partition的更多相关文章

  1. [LeetCode] Equal Tree Partition 划分等价树

    Given a binary tree with n nodes, your task is to check if it's possible to partition the tree to tw ...

  2. 663. Equal Tree Partition 能否把树均分为求和相等的两半

    [抄题]: Given a binary tree with n nodes, your task is to check if it's possible to partition the tree ...

  3. [leetcode-663-Equal Tree Partition]

    Given a binary tree with n nodes, your task is to check if it's possible to partition the tree to tw ...

  4. [LeetCode] 663. Equal Tree Partition 划分等价树

    Given a binary tree with n nodes, your task is to check if it's possible to partition the tree to tw ...

  5. 【LeetCode】663. Equal Tree Partition 解题报告 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 日期 题目地址:https://leetcode ...

  6. The 2019 ICPC Asia Shanghai Regional Contest H Tree Partition k、Color Graph

    H题意: 给你一个n个节点n-1条无向边构成的树,每一个节点有一个权值wi,你需要把这棵树划分成k个子树,每一个子树的权值是这棵子树上所有节点权值之和. 你要输出这k棵子树的权值中那个最大的.你需要让 ...

  7. python 常忘代码查询 和autohotkey补括号脚本和一些笔记和面试常见问题

    笔试一些注意点: --,23点43 今天做的京东笔试题目: 编程题目一定要先写变量取None的情况.今天就是因为没有写这个边界条件所以程序一直不对.以后要注意!!!!!!!!!!!!!!!!!!!!! ...

  8. LeetCode All in One题解汇总(持续更新中...)

    突然很想刷刷题,LeetCode是一个不错的选择,忽略了输入输出,更好的突出了算法,省去了不少时间. dalao们发现了任何错误,或是代码无法通过,或是有更好的解法,或是有任何疑问和建议的话,可以在对 ...

  9. All LeetCode Questions List 题目汇总

    All LeetCode Questions List(Part of Answers, still updating) 题目汇总及部分答案(持续更新中) Leetcode problems clas ...

  10. Leetcode problems classified by company 题目按公司分类(Last updated: October 2, 2017)

    All LeetCode Questions List 题目汇总 Sorted by frequency of problems that appear in real interviews. Las ...

随机推荐

  1. MaxKB+Ollama 离线部署

    主题:在 Centos7 环境部署 MaxKB 以及 Ollama 实现基于离线大模型的的小助手调用. 选择离线部署的原因:原计划是打算直接使用 1Panel 进行 MaxKB 和 Ollama 一键 ...

  2. 【JDBC第9章】Apache-DBUtils实现CRUD操作

    第9章:Apache-DBUtils实现CRUD操作 9.1 Apache-DBUtils简介 commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的 ...

  3. 【电脑】重装Win10之后无法唤醒和正常关机(Y9000P 2022)

    问题: Y9000P 2022 改Windows10后经常关机关不全(自带键盘灯亮,电源指示灯不灭),这还不是最重要的,它一会儿不用到时间自动休眠后还经常唤醒不了 解决: 两个问题,总结一下: 一.关 ...

  4. 使用Python对理想气体进行建模

    引言 在日常生活中,我们常常听到"气体",但你是否知道气体的行为是如何被科学家们用数学模型描述的呢?今天,我们就来聊聊如何用 Python 对理想气体进行建模,帮助大家更好地理解气 ...

  5. Ruby+Selenium+testunit web自动化demo

    1.安装对应库 使用RubyMine新建项目打开终端安装对应库 gem install selenium-webdriver gem install test-unit 如果安装不成功,请切换到国内源 ...

  6. VMware平台的Ubuntu部署完全分布式Hadoop环境

    前言: 此文章是本人初次部署Hadoop的过程记录以及所遇到的问题解决,这篇文章只有实际操作部分,没有理论部分.因本人水平有限,本文难免存在不足的地方,如果您有建议,欢迎留言或私信告知于我,非常感谢. ...

  7. eolinker环境变量配置:用例执行前给把某参数设置为全局参数的方法

    特别注意:需要使用全局变量或者预处理前务必阅读本链接https://www.cnblogs.com/becks/p/13713278.html 1.场景分析 注册会员流程共计有添加数据,校验数据,提交 ...

  8. WPF封装一个懒加载下拉列表控件(支持搜索)

    因为项目中PC端前端针对基础数据选择时的下拉列表做了懒加载控件,PC端使用现成的组件,为保持两端的选择方式统一,WPF客户端上也需要使用懒加载的下拉选择. WPF这种懒加载的控件未找到现成可用的组件, ...

  9. 鸿蒙Next开发实战教程—电影app

    最近忙忙活活写了不少教程,但是总感觉千篇一律,没什么意思,大家如果有感兴趣的项目可以私信给幽蓝君写一写. 今天分享一个电影App.   这个项目也比较简单,主要是一些简单页面的开发和本地视频的播放以及 ...

  10. Form验证实例

    程序目录 models.py from django.db import models# Create your models here.class UserInfo(models.Model):   ...