【loj3044】【zjoi2019】Minimax
题目
描述
给出一颗树,定义根节点1的深度为1,其他点深度为父亲深度+1;
如下定义一个点的点权:
1.叶子:为其编号;2.奇数深度:为其儿子编号最大值;3.偶数深度:为其儿子编号最小值;
对于一个叶子集合 \(S\) ,你可以修改 $w_i \to w_i \pm C ,i \in S $ , 称使得根权值改变的最小\(C\)为\(S\)的稳定度;(如果无论如何根都不变规定稳定度为\(n\))
询问稳定度为 \(i \in [L,R]\) 的有多少个,对每个 \(i\) 依次输出;
范围
$2 \le n \le 2 \times 10^5 \ , \ 1 \le L \le R \le n $
题解
由于点权互不相同,所以一定可以找到一条到某个叶子的链:链上的值都是根节点的值,记这个链为\(key\) ,并且顶点的权值改变的充要条件是\(key\)上某个点改变。考虑统计不改变的情况,对\(key\)上每个点分奇偶做一个 \(dp\) 再相乘,可以求出不变方案数,获得了一个 \(O(n(R-L))\) 的算法。
从小到大考虑 \(C\) ,每个叶子的初始值只会改变一次,用\(ddp\)维护即可。注意由于系数有0需要特判一下;
#include<bits/stdc++.h>
#define mod 998244353
#define ll long long
#define ls (k<<1)
#define rs (k<<1|1)
#define mk make_pair
#define pir pair<int,int>
#define fi first
#define se second
#define il inline
#define rg register
using namespace std;
const int N=200010;
int n,L,R,o=1,hd[N],d[N],f[N],g[N],col[N],dep[N],lf[N],id[N];
int fa[N],sz[N],sn[N],st[N],tp[N],dn[N],idx,now,ans[N],cnt,tot;
struct Edge{int v,nt;}E[N<<1];
struct data{
int a,b;
il data operator +(const data&A)const{
data ret;
ret.a=(ll)a*A.a%mod;
ret.b=((ll)A.b*a%mod+b)%mod;
return ret;
}//维护ax+b的迭代;
}tr[N<<2];
il int pw(int x,int y){
int re=1;x%=mod;
while(y){
if(y&1)re=(ll)re*x%mod;
y>>=1;x=(ll)x*x%mod;
}
return re;
}
pir a[N];int b[N];
il int val(pir A){return A.se?0:A.fi;}
il pir operator +(pir A,int B){if(!B)A.se++;else A.fi=(ll)A.fi*B%mod;return A;}
il pir operator -(pir A,int B){if(!B)A.se--;else A.fi=(ll)A.fi*pw(B,mod-2)%mod;return A;}
//用来处理ax+b系数a为0的情况;
il char gc(){
static char*p1,*p2,s[1000000];
if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
return(p1==p2)?EOF:*p1++;
}
il int rd(){
int x=0;char c=gc();
while(c<'0'||c>'9')c=gc();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
return x;
}
il void adde(int u,int v){
d[u]++,d[v]++;
E[o]=(Edge){v,hd[u]};hd[u]=o++;
E[o]=(Edge){u,hd[v]};hd[v]=o++;
}
il void Min(int&x,int y){if(x>y)x=y;}
il void Max(int&x,int y){if(x<y)x=y;}
void dfs_pre(int u,int F){
dep[u]=dep[fa[u]=F]+1;sz[u]=1;
if(u!=1&&d[u]==1){lf[u]=2;f[u]=dn[u]=u;return;}
lf[u]=1;f[u]=dep[u]&1?0:n;
for(rg int i=hd[u];i;i=E[i].nt){
int v=E[i].v;
if(v==F)continue;
dfs_pre(v,u);
sz[u]+=sz[v];lf[u]=(ll)lf[u]*lf[v]%mod;
if(sz[sn[u]]<sz[v])sn[u]=v,dn[u]=dn[v];
if(dep[u]&1)Max(f[u],f[v]);else Min(f[u],f[v]);
}
}
//以下为朴素dp部分:
//***************************************
void dfs_mn(int u,int T){
st[++idx]=u;id[u]=idx;
tp[u]=T;g[u]=1;col[u]=1;
if(u!=1&&d[u]==1){a[u]=mk(0,0),b[u]=g[u]=(u<=f[1])<<1;return;}
if(dep[u]&1){
a[u]=mk(1,0);b[u]=0;
dfs_mn(sn[u],T);
g[u]=(ll)g[u]*g[sn[u]]%mod;
for(rg int i=hd[u];i;i=E[i].nt){
int v=E[i].v;
if(v==fa[u]||v==sn[u])continue;
dfs_mn(v,v);
g[u]=(ll)g[u]*g[v]%mod;
a[u]=a[u]+g[v]%mod;
}
}else{
a[u]=mk(1,0);
dfs_mn(sn[u],T);
g[u]=(ll)g[u]*(lf[sn[u]]-g[sn[u]]+mod)%mod;
for(rg int i=hd[u];i;i=E[i].nt){
int v=E[i].v;
if(v==fa[u]||v==sn[u])continue;
dfs_mn(v,v);
g[u]=(ll)g[u]*(lf[v]-g[v]+mod)%mod;
a[u]=a[u]+((lf[v]-g[v]+mod)%mod);
}
g[u]=(lf[u]-g[u]+mod)%mod;
b[u]=(lf[u]-(ll)val(a[u])*lf[sn[u]]%mod+mod)%mod;
}
}
void dfs_mx(int u,int T){
st[++idx]=u;id[u]=idx;
tp[u]=T;g[u]=1;col[u]=2;
if(u!=1&&d[u]==1){a[u]=mk(0,0),b[u]=g[u]=(u>=f[1])<<1;return;}
if(dep[u]&1){
a[u]=mk(1,0);
dfs_mx(sn[u],T);
g[u]=(ll)g[u]*(lf[sn[u]]-g[sn[u]]+mod)%mod;
for(rg int i=hd[u];i;i=E[i].nt){
int v=E[i].v;
if(v==fa[u]||v==sn[u])continue;
dfs_mx(v,v);
g[u]=(ll)g[u]*(lf[v]-g[v]+mod)%mod;
a[u]=a[u]+(lf[v]-g[v]+mod)%mod;
}
g[u]=(lf[u]-g[u]+mod)%mod;
b[u]=(lf[u]-(ll)val(a[u])*lf[sn[u]]%mod+mod)%mod;
}else{
a[u]=mk(1,0);b[u]=0;
dfs_mx(sn[u],T);
g[u]=(ll)g[u]*g[sn[u]]%mod;
for(rg int i=hd[u];i;i=E[i].nt){
int v=E[i].v;
if(v==fa[u]||v==sn[u])continue;
dfs_mx(v,v);
g[u]=(ll)g[u]*g[v]%mod;
a[u]=a[u]+g[v]%mod;
}
}
}
void dfs_key(int u){
for(rg int i=hd[u];i;i=E[i].nt){
int v=E[i].v;
if(v==fa[u])continue;
if(f[u]==f[v]){dfs_key(v);continue;}
if(dep[u]&1)dfs_mn(v,v);else dfs_mx(v,v);
now=(ll)now*g[v]%mod;
}
}
//******************************************
il void pushup(int k){tr[k]=tr[ls]+tr[rs];}
void build(int k,int l,int r){
if(l==r){tr[k]=(data){val(a[st[l]]),b[st[l]]};return;}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(k);
}
void update(int k,int l,int r,int x){
/*{
cnt++;
}*/
if(l==r){tr[k]=(data){val(a[st[l]]),b[st[l]]};return;}
int mid=l+r>>1;
if(x<=mid)update(ls,l,mid,x);
else update(rs,mid+1,r,x);
pushup(k);
}
data query(int k,int l,int r,int x,int y){
/*{
cnt++;
}*/
if(l==x&&r==y)return tr[k];
int mid=l+r>>1;
if(y<=mid)return query(ls,l,mid,x,y);
else if(x>mid)return query(rs,mid+1,r,x,y);
else return query(ls,l,mid,x,mid)+query(rs,mid+1,r,mid+1,y);
}
il void Update_mn(int u){
int tmp,tu,du,v;
a[u]=mk(0,0),b[u]=1;
while(1){
tot++;
tu=tp[u];du=dn[u];
update(1,1,n,id[u]);
tmp=g[tu],g[tu]=query(1,1,n,id[tu],id[du]).b;
v=tu,u=fa[tu];
if(!col[u])break;
if(dep[u]&1){
a[u]=a[u]-tmp+g[v];
b[u]=0;
}else {
a[u]=a[u]-(lf[v]-tmp+mod)%mod+(lf[v]-g[v]+mod)%mod;
b[u]=(lf[u]-(ll)lf[sn[u]]*val(a[u])%mod+mod)%mod;
}
}
now=(ll)now*pw(tmp,mod-2)%mod*g[v]%mod;
}
il void Update_mx(int u){
int tmp,tu,du,v;
a[u]=mk(0,0),b[u]=1;
while(1){
tot++;
tu=tp[u];du=dn[u];
update(1,1,n,id[u]);
tmp=g[tu],g[tu]=query(1,1,n,id[tu],id[du]).b;
v=tu,u=fa[tu];
if(!col[u])break;
if(dep[u]&1){
a[u]=a[u]-(lf[v]-tmp+mod)%mod+(lf[v]-g[v]+mod)%mod;
b[u]=(lf[u]-(ll)lf[sn[u]]*val(a[u])%mod+mod)%mod;
}else{
a[u]=a[u]-tmp+g[v];
b[u]=0;
}
}
now=(ll)now*pw(tmp,mod-2)%mod*g[v]%mod;
}
char ps[1000000],*pp=ps;
void push(char x){
if(pp==ps+1000000)fwrite(ps,1,1000000,stdout),pp=ps;
*pp++=x;
}
void write(int x){
if(!x){push('0');push(' ');return;}
static int sta[20],top;
while(x)sta[++top]=x%10,x/=10;
while(top)push(sta[top--]^'0');
push(' ');
}
void flush(){fwrite(ps,1,pp-ps,stdout);}
int main(){
//freopen("minimax.in","r",stdin);
//freopen("minimax.out","w",stdout);
n=rd();L=rd();R=rd();
for(rg int i=1;i<n;++i)adde(rd(),rd());
dfs_pre(1,0);
now=1;dfs_key(1);
ans[1]=(lf[1]-now+mod)%mod;
build(1,1,n);
//cerr<<fixed<<setprecision(2)<<1.0*clock()/CLOCKS_PER_SEC<<endl;
for(rg int i=2,j1=f[1]-1,j2=f[1]+1;i<n;++i){
while(j1>=1&&j1+i>f[1]){if(d[j1]==1&&col[j1]==1)Update_mn(j1);j1--;}
while(j2<=n&&j2-i<f[1]){if(d[j2]==1&&col[j2]==2)Update_mx(j2);j2++;}
ans[i]=(lf[1]-now+mod)%mod;
/*if(i==1000){
write(cnt);
write(tot);
break;
}*/
// cerr<<fixed<<setprecision(2)<<1.0*clock()/CLOCKS_PER_SEC<<endl;
}
ans[n]=lf[1]-1;
for(rg int i=n;i;--i)ans[i]=(ans[i]-ans[i-1]+mod)%mod;
for(rg int i=L;i<=R;++i)write(ans[i]);//printf("%d ",ans[i]);
flush();
//printf("%.2lf\n",1.0*clock()/CLOCKS_PER_SEC);
//cerr<<fixed<<setprecision(2)<<1.0*clock()/CLOCKS_PER_SEC<<endl;
return 0;
}
【loj3044】【zjoi2019】Minimax的更多相关文章
- 【LOJ】#3044. 「ZJOI2019」Minimax 搜索
LOJ#3044. 「ZJOI2019」Minimax 搜索 一个菜鸡的50pts暴力 设\(dp[u][j]\)表示\(u\)用\(j\)次操作能使得\(u\)的大小改变的方案数 设每个点的初始答案 ...
- 【疯狂造轮子-iOS】JSON转Model系列之二
[疯狂造轮子-iOS]JSON转Model系列之二 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇<[疯狂造轮子-iOS]JSON转Model系列之一> ...
- 【疯狂造轮子-iOS】JSON转Model系列之一
[疯狂造轮子-iOS]JSON转Model系列之一 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 之前一直看别人的源码,虽然对自己提升比较大,但毕竟不是自己写的,很容易遗 ...
- 【原创分享·支付宝支付】HBuilder打包APP调用支付宝客户端支付
前言 最近有点空余时间,所以,就研究了一下APP支付.前面很早就搞完APP的微信支付了,但是由于时间上和应用上的情况,支付宝一直没空去研究.然后等我空了的时候,发现支付宝居然升级了支付逻辑,虽然目前还 ...
- 【AutoMapper官方文档】DTO与Domin Model相互转换(上)
写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...
- 【Win 10 应用开发】应用预启动
所谓预启动,其实你一看那名字就知道是啥意思了,这是直接译,也找不到比这个叫法更简练的词了.在系统资源允许的情况下(比如电池电量充足,有足够的内存空间),系统会把用户常用的应用程序在后台启动,但不会显示 ...
- 【Win 10 应用开发】启动远程设备上的应用
这个功能必须在“红石-1”(build 14393)以上的系统版中才能使用,运行在一台设备上的应用,可以通过URI来启动另一台设备上的应用.激活远程应用需要以下前提: 系统必须是build 14393 ...
- 【开源】分享2011-2015年全国城市历史天气数据库【Sqlite+C#访问程序】
由于个人研究需要,需要采集天气历史数据,前一篇文章:C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子),介绍了基本的采集思路和核心代码,经过1个星期的采集,历史数据库 ...
- 【原创分享·微信支付】C# MVC 微信支付教程系列之现金红包
微信支付教程系列之现金红包 最近最弄这个微信支付的功能,然后扫码.公众号支付,这些都做了,闲着无聊,就看了看微信支付的其他功能,发现还有一个叫“现金红包”的玩意,想 ...
- 【原创分享·微信支付】 C# MVC 微信支付教程系列之扫码支付
微信支付教程系列之扫码支付 今天,我们来一起探讨一下这个微信扫码支付.何为扫码支付呢?这里面,扫的码就是二维码了,就是我们经常扫一扫的那种二维码图片,例如,我们自己添 ...
随机推荐
- Vue Element Tabe Pager 分页方案
表格和分页分离的,但是使用中,却是结合在一起的. 分析 有以下方式触发查询: mounted 加载数据. 查询按钮 加载数据. pager 变化加载数据 加载数据函数: loadData 问题 mou ...
- python基础学习笔记(六)
学到这里已经很不耐烦了,前面的数据结构什么的看起来都挺好,但还是没法用它们做什么实际的事. 基本语句的更多用法 使用逗号输出 >>> print 'age:',25 age: 25 ...
- JS 实现计算一段文字中的字节数,字母数,数字数,行数,汉字数。
看到了匹配,第一个想到了用正则表达式,哈哈,果然很方便.不过正则表达式高深莫测!我还没有研究明白啊..目前学了点皮毛.代码如下: <!DOCTYPE html PUBLIC "-//W ...
- M2postmortem
设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 答:我们的软件主要解决信息提取的问题.定义清晰:要提取的内容包括于计算机科学相关内容的标题.作者. ...
- 20135327郭皓--Linux内核分析第七周 可执行程序的装载
第七周 可执行程序的装载 郭皓 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 ...
- 同步手绘板——将View的内容映射成Bitmap转图片导出
在Android中自有获取view中的cache内容,然后将内容转换成bitmap,方法名是:getDrawingCache(),返回结果为Bitmap,但是刚开始使用的时候,得到的结果都是null, ...
- 数学战神app(小学生四则运算app)进度
背景音乐仍有瑕疵,还在完善,不过大概完成,完善按钮声音,提示音等. 许家豪:负责代码程序设计 陈思明:界面背景美化 吴旭涛.王宏财:查缺补漏
- zookeeper安装和使用 windows环境(转)
原文地址: http://blog.csdn.net/tlk20071/article/details/52028945 简介 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是G ...
- Beta阶段敏捷冲刺一
一.举行站立式会议 1.当天站立式会议照片一张 2.团队成员报告 林楚虹 (1) 昨天已完成的工作:查找连接数据库有关资料,请教在上一轮已经连接成功的同学 (2) 今天计划完成的工作:连接上数据库 ( ...
- git使用命令记录
一,两个概念:1.工作区:你电脑里能看见的目录,比如一个项目文件夹就是一个工作区2.版本库工作区(该项目的文件夹)中有一个隐藏文件 .git ,就是git的版本库.(这个文件默认是隐藏,Ctrl+h ...