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. Ceph-集群内分布式存储解决方案及基于Docker的部署

    打造集群高可用分布式存储Ceph很早以前在玩集群的时候就折腾过分布式存储服务来作为跨节点的数据共享和可靠存储,以前尝试过GlusterFS,但是由于读写速度实在是太低,就放弃了.见基于GlusterF ...

  2. oracle数据库体系架构详解

    在学习oracle中,体系结构是重中之重,一开始从宏观上掌握它的物理组成.文件组成和各种文件组成.掌握的越深入越好.在实际工作遇到疑难问题,其实都可以归结到体系结构中来解释.体系结构是对一个系统的框架 ...

  3. Win7共享账号切换程序

    服务器共享目录需要多账号登录时,需要重启电脑才可切换不同账号登 为了不重启电脑就可立即切换不同账号登,特意写了此款软件, 下载: 链接:https://pan.baidu.com/s/1g_4SCXl ...

  4. CMake简单学习

    CMake 说明 cmake的定义是什么 ?-----高级编译配置工具 当多个人用不同的语言或者编译器开发一个项目,最终要输出一个可执行文件或者共享库(dll,so等等)这时候神器就出现了-----C ...

  5. .net 跨域 config中配置

    <system.webServer> <validation validateIntegratedModeConfiguration="false" /> ...

  6. 【Java】各种代码块的执行顺序

    静态代码块:用staitc声明,jvm加载类时执行,仅执行一次 构造代码块:类中直接用{}定义,每一次创建对象时执行. 执行顺序优先级:静态块,main(),构造块,构造方法. 构造函数 public ...

  7. 【SpringMVC】RESTful CRUD

    RESTful CRUD REST:即 Representational State Transfer.(资源)表现层状态转化.是目前最流行的一种互联网软件架构.它结构清晰.符合标准.易于理解.扩展方 ...

  8. 独家推荐!这款端到端AI测试工具 Testim,让效率飙升!(支持移动端、Web端)

    在当今快速发展的软件开发时代,确保软件质量成为每个开发团队的首要任务. 随着人工智能(AI)和机器学习(ML)技术的飞速发展,AI测试工具应运而生,为软件测试领域带来了革命性的变化.今天,我要向大家强 ...

  9. tomcat非root用户启动

    部署远程服务器时候, 基本都是用root账户登录, 习惯上会直接使用root启动tomcat. 这样其实是有风险的, 黑客获取的权限即容器的权限, 如果容器运行权限就很高,被攻破黑客即可获取很高的权限 ...

  10. 你常用哪些工具来分析 JVM 性能?

    常用的 JVM 性能分析工具 JVM 性能分析工具主要用于监控.调试和优化 Java 程序的性能,尤其是在垃圾回收.内存泄漏.线程调度等方面.以下是一些常用的 JVM 性能分析工具: 1. jvisu ...