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 ...
随机推荐
- 前端视角看 HTTPS
最近用Docusaurus搭了一个个人网站,部署后看到浏览器地址栏上"不安全"三个字感觉特别辣眼,便不由自主的想起了HTTPS.回忆起自己在日常开发中遇到的一些与HTTPS相关的知 ...
- 13. Docker-compose容器编排(详解说明)
13. Docker-compose容器编排(详解说明) @ 目录 13. Docker-compose容器编排(详解说明) 1. Docker-compose容器编排概述 2. Docker-Com ...
- 【攻防世界】wife_wife
wife_wife 题目来源 攻防世界 NO.GFSJ1192 题解 本题没有源码,也没有提示,非常困难,在网上搜索此题可以看到源码.由于使用了assign(),因此存在Javascript原型链污染 ...
- Elasticsearch7.8搭建(Windows版本单节点、Linux版本单节点、集群,)
The Elastic Stack, 包括 Elasticsearch.Kibana.Beats 和 Logstash(也称为 ELK Stack).能够安全可靠地获取任何来源.任何格式的数据,然后实 ...
- 《HelloGitHub》第 107 期
兴趣是最好的老师,HelloGitHub 让你对开源感兴趣! 简介 HelloGitHub 分享 GitHub 上有趣.入门级的开源项目. github.com/521xueweihan/HelloG ...
- 「六」Goaccess实现可视化
下载 apt install goaccess 使用goaccess进行监控 LANG="en_US.UTF-8" bash -c 'goaccess logs/access.lo ...
- 运算符“<”不能应用于类型“boolean”和“RegExp”。ts-plugin(2365)
在使用vue3 + setup + ts + volar插件开发时,遇到文件全红报这个错,尝试很多方法没有效果,最后把vscode插件全部卸载,然后重新安装就好了,如果有遇到此问题的可以尝试同样的方法 ...
- laradock 安装扩展程序 pcntl
起因 运行workman脚步的时候,PHP 提示缺少 pcntl 扩展 Config git:(master) php start.php -d Please install pcntl extens ...
- 堆排序(topk 问题)(NB)
博客地址:https://www.cnblogs.com/zylyehuo/ # _*_coding:utf-8_*_ # 比较排序 import random def sift(li, low, h ...
- Redis 原理 - Hash
Hash 数据结构 使用 ziplist 当同时满足下面两个条件时,使用 ziplist 存储数据 元素个数少于512个 (hash-max-ziplist-entries: 512) 每个元素长度小 ...