容斥,强制若干条链不重要,即有$2^{n-1-s}$种(其中$s$为这些链的并所覆盖的边数),暴力将选中的链打标记,时间复杂度$o(m^{2}2^{m}+n\log_{2}n)$(预处理出这$2m$个点的虚树),期望得分32(实际得分40)

考虑在计算$s$时可以差分来统计,时间复杂度可以做到$o(m2^{m}+n\log_{2}n)$,期望得分40

考虑另一种优化方法:按照dfs的顺序去枚举,每一次枚举$v=k$的所有链的状态,并维护当前子树内的被选择的深度最小的$u$(如果$u$在$k$子树中令$u=k$),这样的时间复杂度也是$o(m2^{m}+n\log_{2}n)$

观察到当处理完$k$子树后,影响答案的只有:1.深度最小的$u$(的深度);2.所覆盖的边数$s$(仅考虑子树内部),那么用$f[k][u][s]$表示对应的方案数(方案有“正负”),时间复杂度$o(n^{4})$

考虑优化,不妨令$dp[k][u]=\sum_{i=0}^{n-1}f[k][u][i]\cdot 2^{sz[k]-1-i}$,后者具有可乘性,因此可以转移(注意:转移过程中$sz[k]-1$的意义为考虑过的边数量),时间复杂度$o(n^{2})$

记$S[k][u]=\sum_{i=u}^{dep_{k}}dp[k][i]$,简单化简,可以发现新的转移式为$S[k][u]=\prod_{son}(S[son][u]+S[son][dep_{son}])$

考虑用线段树来维护这个dp数组,那么要支持:1.区间加;2.对应位置相乘

维护加法标记和乘法标记,然后线段树合并即可,时间复杂度$o(n\log_{2}n)$

 1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 500005
4 #define mod 998244353
5 #define mid (l+r>>1)
6 #define pii pair<int,int>
7 #define fi first
8 #define se second
9 struct ji{
10 int nex,to;
11 }edge[N<<1];
12 vector<int>v[N];
13 int V,E,n,m,x,y,head[N],s[N],r[N],ls[N*40],rs[N*40];
14 pii tag[N*40];
15 void add(int x,int y){
16 edge[E].nex=head[x];
17 edge[E].to=y;
18 head[x]=E++;
19 }
20 void upd(int k,pii x){
21 tag[k].fi=1LL*tag[k].fi*x.fi%mod;
22 tag[k].se=(1LL*tag[k].se*x.fi+x.se)%mod;
23 }
24 void down(int k){
25 if (ls[k])upd(ls[k],tag[k]);
26 if (rs[k])upd(rs[k],tag[k]);
27 tag[k]=make_pair(1,0);
28 }
29 void update(int &k,int l,int r,int x,int y,int z){
30 if ((l>y)||(x>r))return;
31 if (!k){
32 k=++V;
33 tag[k]=make_pair(1,0);
34 }
35 if ((x<=l)&&(r<=y)){
36 tag[k].fi=(tag[k].fi+z)%mod;
37 return;
38 }
39 down(k);
40 update(ls[k],l,mid,x,y,z);
41 update(rs[k],mid+1,r,x,y,z);
42 }
43 int query(int k,int l,int r,int x){
44 if (l==r)return tag[k].se;
45 down(k);
46 if (x<=mid)return query(ls[k],l,mid,x);
47 return query(rs[k],mid+1,r,x);
48 }
49 int merge(int k1,int k2){
50 if ((!k1)||(!k2))return k1+k2;
51 if ((!ls[k1])&&(!rs[k1]))swap(k1,k2);
52 if ((!ls[k2])&&(!rs[k2])){
53 upd(k1,make_pair(tag[k2].se,0));
54 return k1;
55 }
56 down(k1);
57 down(k2);
58 ls[k1]=merge(ls[k1],ls[k2]);
59 rs[k1]=merge(rs[k1],rs[k2]);
60 return k1;
61 }
62 void dfs(int k,int fa,int sh){
63 s[k]=sh;
64 if (!v[k].size())update(r[k],0,n,0,s[k],1);
65 else{
66 for(int i=1;i<v[k].size();i++)
67 if (s[v[k][i]]>s[v[k][0]])v[k][0]=v[k][i];
68 update(r[k],0,n,s[v[k][0]],s[k],mod-1);
69 }
70 for(int i=head[k];i!=-1;i=edge[i].nex)
71 if (edge[i].to!=fa){
72 dfs(edge[i].to,k,sh+1);
73 r[k]=merge(r[k],r[edge[i].to]);
74 }
75 if (k>1)update(r[k],0,n,0,s[k],query(r[k],0,n,s[k]));
76 }
77 int main(){
78 freopen("destiny.in","r",stdin);
79 freopen("destiny.out","w",stdout);
80 scanf("%d",&n);
81 memset(head,-1,sizeof(head));
82 for(int i=1;i<n;i++){
83 scanf("%d%d",&x,&y);
84 add(x,y);
85 add(y,x);
86 }
87 scanf("%d",&m);
88 for(int i=1;i<=m;i++){
89 scanf("%d%d",&x,&y);
90 v[y].push_back(x);
91 }
92 dfs(1,0,0);
93 printf("%d",query(r[1],0,n,0));
94 return 0;
95 }

[loj3340]命运的更多相关文章

  1. 一个页面实例化两个ueditor编辑器,同样的出生却有不同的命运

    今天遇到一个比较怪异的问题,有一项目需要在同一个页面上展现两个ueditor编辑器,在展现时并不任何问题,但当点击了“保存”按钮时就出错了,有其中一个ueditor在asp.net中无法获取编辑器的值 ...

  2. HDU 2571 命运

    命运 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...

  3. HDUOJ----2571(命运)(简单动态规划)

    命运 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submiss ...

  4. HDU 2571 命运 动态规划

    命运 http://acm.hdu.edu.cn/showproblem.php?pid=2571 Problem Description 穿过幽谷意味着离大魔王lemon已经无限接近了!可谁能想到, ...

  5. HDU 2571 命运 (DP)

    命运 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Pr ...

  6. hdu2571 命运 动态规划Dp

    转载请注明出处:http://blog.csdn.net/u012860063 题目链接:pid=2571" target="_blank">http://acm. ...

  7. HDU-2571命运

    Problem Description 穿过幽谷意味着离大魔王lemon已经无限接近了!可谁能想到,yifenfei在斩杀了一些虾兵蟹将后,却再次面临命运大迷宫的考验,这是魔王lemon设下的又一个机 ...

  8. 命运(HDU 2571 简单动态规划)

    命运 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...

  9. hdu 2571 命运(dp)

    Problem Description 穿过幽谷意味着离大魔王lemon已经无限接近了! 可谁能想到,yifenfei在斩杀了一些虾兵蟹将后,却再次面临命运大迷宫的考验,这是魔王lemon设下的又一个 ...

随机推荐

  1. SpringBoot如何实现定时任务

    写在前面 SpringBoot创建定时任务的方式很简单,主要有两种方式:一.基于注解的方式(@Scheduled)二.数据库动态配置.实际开发中,第一种需要在代码中写死表达式,如果修改起来,又得重启会 ...

  2. 创建线程的4种方法 and 线程的生命周期

    线程的启动和运行 方法一:使用start()方法:用来启动一个线程,当调用start方法后,JVM会开启一个新线程执行用户定义的线程代码逻辑. 方法二:使用run()方法:作为线程代码逻辑的入口方法. ...

  3. Mybatis 二级缓存应用 (21)

    [MyBatis 二级缓存] 概述:一级缓存作用域为同一个SqlSession对象,而二级缓存用来解决一级缓存不能夸会话共享,作用范围是namespace级,可以被多个SqlSession共享(只要是 ...

  4. 想要彻底搞懂大厂是如何实现Redis高可用的?看这篇文章就够了!(1.2W字,建议收藏)

    高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间. 假设系统一直能够提供服务,我们说系统的可用性是100%.如果 ...

  5. Less-23 preg_replace1

    Less-23: 直接跳到Less-23的原因是,Less-(11~22)均为注入点不为get方式的注入.我先把get型注入写的差不多,再回来整理关于注入点的内容. 核心语句: 查询.报错均有回显. ...

  6. 【c++ Prime 学习笔记】第12章 动态内存

    对象的生存期: 全局对象:程序启动时创建,程序结束时销毁 局部static对象:第一次使用前创建,程序结束时销毁 局部自动对象:定义时创建,离开定义所在程序块时销毁 动态对象:生存期由程序控制,在显式 ...

  7. 【数据结构与算法Python版学习笔记】树——二叉树的应用:解析树

    解析树(语法树) 将树用于表示语言中句子, 可以分析句子的各种语法成分, 对句子的各种成分进行处理 语法分析树 程序设计语言的编译 词法.语法检查 从语法树生成目标代码 自然语言处理 机器翻译 语义理 ...

  8. 5.29日 Scrum Metting

    日期:2021年5月29日 会议主要内容概述:人员调整,xyl同时兼顾前后端:确定表格缩放策略和新图表添加:强调任务分配,总结工作. 一.进度情况## 组员 负责 两日内已完成的工作 后两日计划完成的 ...

  9. Vue3+Typescript+Node.js实现微信端公众号H5支付(JSAPI v3)教程--各种填坑

    ----微信支付文档,不得不说,挺乱!(吐槽截止) 功能背景 微信公众号中,点击菜单或者扫码,打开公众号中的H5页面,进行支付. 一.技术栈 前端:Vue:3.0.0,typescript:3.9.3 ...

  10. 浅谈如何爆踩TLEcoders

    对付一些速度比老奶奶都慢的评测姬, 除了超级小的常数,往往还不得不使用一些不算办法的办法 比如说这个让人无语的$ACcoders$的评测姬, 当我们感到代码已经无法再卡常的时候,对人生已经近乎绝望的时 ...