CF1930G Prefix Max Set Counting 题解
题意:
给定一棵以 1 为根的有根树,求出其所有 dfs 序中前缀最大值序列的数量。\(n\le 10^6\)。
思路
显然考虑 DP。
由于是求前缀最大值序列的方案数,因此如果一些点要出现在这个序列中,其到根节点上一定没有比它大的节点。
因此我们设 \(f_i\) 表示以权值为 \(i\) 的点为结尾的序列数量。可以发现权值最大的一定在这个序列末尾,权值最小的根节点 1 一定在这个序列的开头,因此这个 DP 的初始状态是 \(f_1=1\),答案就是 \(f_n\)。
我们定义某个点对另一些点“有贡献” 指这另一些点的方案数可以从这个点转移过来。具体而言,这个转移就是使当前点作为序列倒数第二个点,被贡献的点作为第一个点,去加被贡献的点的方案数。
发现如果按树点的权值顺序从小到大枚举,可以通过刷表法来维护某一个点。因为只有小的点可能对大的点有贡献,而大的点不可能对小的点有贡献,因此这样统计是完备的。
按这个思路,我们来分类讨论就可以计算贡献了。假设当前点为 \(i\),其权值同样也为 \(i\)。(注意我们是按权值大小的顺序枚举的)
以 \(i\) 为根的子树内没有比它大的点。
那就考虑它什么时候可以作为序列的倒数第二个点。我们向上枚举 \(i\) 的祖先 \(u\),假设 \(u\) 及其子树中权值最大的点是 \(j\),那么当 \(j>i\) 的时候,\(u\) 及其子树中的点就有了一种走的方式:
先走到 \(i\),再走到 \(j\) 就保证以 \(j\) 自己结尾的方案数必定可以累加上 \(i\) 的方案数。因此我们直接给 \(u\) 子树中权值比 \(i\) 大的方案数加上 \(f_i\) 即可。
注意这里找 \(u\) 可以直接暴力跳父亲,因为有均摊,找 \(u\) 的总复杂度 \(O(n)\)。以 \(i\) 为根的子树内有比其大的点。
因为 dfs 序是一定要一棵子树搜完以后再去其他子树,因此对于除了以 \(i\) 为根的其他子树而言 \(i\) 作为序列的倒数第二位已经不可能了。
因此直接将 \(i\) 自己子树中权值大于 \(i\) 的节点的方案数加上 \(f_i\) 即可。
然后发现由于权值比 \(i\) 小的所有数全部都已经枚举完了,加不加无所谓,因此加的时候不需要管权值是否大于 \(i\),直接把整棵子树全部都加即可。
于是差分后的树状数组即可满足条件。在 dfs 序上维护,区间加单点查。
code
事实上感觉没有黑题的难度。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+7,p=998244353;
int n,f[N],fa[N],siz[N],dfncnt,dfn[N],mson[N],sign[N],tot[N];
vector<int> q[N];
struct node{
int tr[N];
void modify(int x,int val){while(x<=n)tr[x]=(tr[x]+val)%p,x+=x&(-x);}
int query(int x){int res=0;while(x)res=(res+tr[x])%p,x-=x&(-x);return res;}
}g;
void dfs1(int u,int fr,int t){
siz[u]=1;fa[u]=fr;dfn[u]=++dfncnt;mson[u]=0;sign[u]=t<u?1:0;
for(int i=0;i<tot[u];i++){
int v=q[u][i];if(v==fr) continue;
dfs1(v,u,max(t,u));siz[u]+=siz[v];mson[u]=max({mson[u],v,mson[v]});
}
}
void solve(){
for(int i=0;i<=n;i++) q[i].clear(),tot[i]=0,f[i]=0,sign[i]=0,g.tr[i]=0;dfncnt=0;
cin>>n;for(int i=1,u,v;i<=n-1;i++){cin>>u>>v;q[u].push_back(v),tot[u]++;q[v].push_back(u),tot[v]++;}
dfs1(1,0,0);f[1]=1;g.modify(1,1);
for(int i=2;i<=n;i++){
if(!sign[i]) continue;
f[i]=g.query(dfn[i]);g.modify(dfn[i]+siz[i],f[i]),g.modify(dfn[i],p-f[i]);
if(i>mson[i]){
int u=i;
while((max(u,mson[u])<=i)&&u) {u=fa[u];}
if(u==0) continue;
g.modify(dfn[u],f[i]);g.modify(dfn[u]+siz[u],p-f[i]);
}
else g.modify(dfn[i],f[i]),g.modify(dfn[i]+siz[i],p-f[i]);
}
cout<<f[n]<<'\n';
}
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int T;cin>>T;while(T--) solve();
return 0;
}
CF1930G Prefix Max Set Counting 题解的更多相关文章
- CSAcademy Prefix Suffix Counting 题解
CSAcademy Prefix Suffix Counting 题解 目录 CSAcademy Prefix Suffix Counting 题解 题意 思路 做法 程序 题意 给你两个数字\(N\ ...
- 【luogu P3128 [USACO15DEC]最大流Max Flow】 题解
题目链接:https://www.luogu.org/problemnew/show/P3128 菜 #include <cstdio> #include <cstring> ...
- [USACO17JAN]Promotion Counting 题解
前言 巨佬说:要有线段树,结果蒟蒻打了一棵树状数组... 想想啊,奶牛都开公司当老板了,我还在这里码代码,太失败了. 话说奶牛开个公司老板不应该是FarmerJohn吗? 题解 刚看到这道题的时候竟然 ...
- POJ 2386 Lake Counting 题解《挑战程序设计竞赛》
地址 http://poj.org/problem?id=2386 <挑战程序设计竞赛>习题 题目描述Description Due to recent rains, water has ...
- CF1106A Lunar New Year and Cross Counting 题解
Content 试求出在一个 \(n\times n\) 的地图 \(M\) 中,满足 \(1\leqslant i,j\leqslant n\) 且 \(M_{i,j}=M_{i+1,j+1}=M_ ...
- 【LeetCode】14. Longest Common Prefix 最长公共前缀
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人公众号:负雪明烛 本文关键词:prefix, 公共前缀,题解,leetcode, 力扣 ...
- 山东省第四届ACM大学生程序设计竞赛解题报告(部分)
2013年"浪潮杯"山东省第四届ACM大学生程序设计竞赛排名:http://acm.upc.edu.cn/ranklist/ 一.第J题坑爹大水题,模拟一下就行了 J:Contes ...
- SP1716 GSS3 - Can you answer these queries III
题面 题解 相信大家写过的传统做法像这样:(这段代码蒯自Karry5307的题解) struct SegmentTree{ ll l,r,prefix,suffix,sum,maxn; }; //.. ...
- [国家集训队2012]middle(陈立杰)
我是萌萌的传送门 我是另一个萌萌的传送门 脑残错误毁一下午…… 其实题解早就烂大街了,然而很久之前我只知道是二分答案+主席树却想不出来这俩玩意儿怎么一块儿用的……今天又翻了几篇题解才恍然大悟,是把权值 ...
- Leetcode: Maximum XOR of Two Numbers in an Array
Given a non-empty array of numbers, a0, a1, a2, - , an-1, where 0 ≤ ai < 231. Find the maximum re ...
随机推荐
- QT5笔记: 31. 文件目录操作
开发的时候,QtCreator F1 查看相关类的信息
- Vigenere密码无密钥求解
0.前言 最近摸了很长时间的鱼,然后最近突然想搞一个Vigenere密码的自动求解,花了不到一天来实现了一下这个东西,不过受限于自己的水平,没有搞的太难.当然,代码部分不是全部都是从 0 开始的,关于 ...
- .net 8 实现 JWT 无状态设计 token [附源码]
本文主要分为两个部分: 1.概念 2..net 8 demo 第一部分主要描述所有与 JWT 相关的概念以及词汇,及其原理:第二部分是代码示例,文末附 源码下载. * 阅读提示 :鼠标悬停在 章节标题 ...
- KTransformer实战DeepSeek-R1-1.58bit量化模型
技术背景 在上一篇文章中,我们介绍过KTransformers大模型高性能加载工具的安装和使用方法.但是当时因为是在一个比较老旧的硬件上面进行测试,其实并没有真正的运行起来.现在补一个在KTransf ...
- golang实现三重DES加密解密
DES DES(Data Encryption)是1977年美国联邦信息处理标准(FIPS)中所采用的一种对称密码(FIPS46-3),一直以来被美国及其他国家的政府和银行等广泛使用.随着计算机的进步 ...
- Django实战项目-学习任务系统-发送邮件通知
接着上期代码内容,继续完善优化系统功能. 本次增加发送邮件通知功能,学习任务系统发布的任务,需要及时通知到学生用户知晓. 由于目前智能手机普及,人人都离不开手机,所以手机端接收通知信息更加及时有效. ...
- Delphi 使用API函数AnimateWindow实现窗体特效功能
API函数 AnimateWindow 使用: 函数功能:窗体显示和隐藏时产生特殊的动画效果:可以产生两种类型的动画效果: 滚动动画 和 滑动动画 函数原型:BOOL AnimateWindow(HW ...
- delphi获得唯一ID字符串
//这是我三层开发中常用的一个函数,直接调用CreateSortID uses System.Win.ComObj,System.RegularExpressions,System.StrUtils, ...
- SSH登录方式及如何防止SSH端口被扫
ssh登录服务器的方式有三种:密码登录,公钥登录,证书登录.同时,密码登录有被破解的风险,网络上也有很多在扫描ssh端口的主机. 比如: 这里175.178.62.36是一个来自广东的服务器,17次尝 ...
- Supergateway:MCP服务器的远程调试与集成工具
Supergateway 是一款专为 MCP(Model Context Protocol)服务器设计的远程调试与集成工具,通过 SSE(Server-Sent Events)或 WebSocket( ...