当前位置:网站首页>P6773 [NOI2020] 命运(dp、线段树合并)
P6773 [NOI2020] 命运(dp、线段树合并)
2022-07-01 01:13:00 【wind__whisper】
前言
一道看起来很毒瘤但其实还算小清新的题?
理解后感觉其实并没有那么难。
暴力分非常足,好评。
奇妙的线段树合并技巧增加了。
解析
解法1
你是怎么手玩的样例一?
大部分(比如我)都是容斥吧。
把手玩的方法搬到代码上就得到了一个从数据范围来看出题人也很想让我们写的 O ( 2 m p o l y ) O(2^mpoly) O(2mpoly) 做法。
仔细想想可以树剖线段树维护没有被覆盖的边的个数,dfs的时候顺便修改,时间复杂度 O ( 2 m log 2 n ) O(2^m\log ^2n) O(2mlog2n)。
期望得分 32-40 分。不太懂为什么网上都是写的 O ( 2 m m log 2 n ) O(2^mm\log ^2n) O(2mmlog2n) 啊
解法2
你不会真的去写解法1了吧。
这个题的形式一看就非常dp。
设计 f x , d f_{x,d} fx,d 表示节点 x x x 的子树处理完毕,没有解决的返祖链的祖先的最大深度为 d d d 的方案数。
容易用类似树上背包的形式转移,时间复杂度 O ( n min ( n , m ) ) O(n\min(n,m)) O(nmin(n,m)),期望得分 64 64 64 分。然而我写的破玩意做不了完全二叉树,结果就只有 56 56 56 分了(悲)。
(前缀和优化的做法写起来更加好写,而且才能引入后面的正解)
解法3
观察dp转移,发现转移非常有规律,似乎可以维护个线段树之类的东西。
然后垃圾的我根本想不到线段树合并,只能想到重链剖分后每个重链维护个线段树,下标只存子树内有的深度限制(类似于离散化),这样所有线段树的叶子个数之和是 O ( n log n ) O(n\log n) O(nlogn),重链处理完后暴力向链头父亲合并,大概是 O ( n log 2 n ) O(n\log^2n) O(nlog2n) 的。
期望得分 88 分。
实现起来非常谔谔,所以只是胡了胡,并没有写。
如果假了的话轻喷(逃
华丽的分割线。然后我的水平就卡在这个地方了。
接下来就是贺题解环节。
解法4
把dp转移写成前缀和形式:
d p x , i = d p x , i ′ ∑ j = 0 d e p x d p s , j + d p x , i ′ ∑ j = 0 i d p s , j + d p s , i ∑ j = 0 i − 1 d p x , j dp_{x,i}=dp'_{x,i}\sum_{j=0}^{dep_x}dp_{s,j}+dp'_{x,i}\sum_{j=0}^{i}dp_{s,j}+dp_{s,i}\sum_{j=0}^{i-1}dp_{x,j} dpx,i=dpx,i′j=0∑depxdps,j+dpx,i′j=0∑idps,j+dps,ij=0∑i−1dpx,j
也就是:
d p x , i = d p x , i ′ ( s u m s , d e p x + s u m s , i ) + d p s , i s u m x , i − 1 dp_{x,i}=dp'_{x,i}(sum_{s,dep_x}+sum_{s,i})+dp_{s,i}sum_{x,i-1} dpx,i=dpx,i′(sums,depx+sums,i)+dps,isumx,i−1
注意到除了 s u m s , d e p x sum_{s,dep_x} sums,depx 是一个常量,其它的东西都与下标密切相关。
考虑线段树合并。
令 s 1 = s u m s , d e p x + s u m s , i , s 2 = s u m x , i − 1 s1=sum_{s,dep_x}+sum_{s,i},s2=sum_{x,i-1} s1=sums,depx+sums,i,s2=sumx,i−1。
在合并时先递归左子树,在递归右子树,不断更新 s 1 , s 2 s1,s2 s1,s2 即可。
我觉得你看看代码可能比听我讲更容易理解。
ll s1,s2;
int merge(int x,int y,int l,int r){
if(!x&&!y) return 0;
else if(!x||!y){
if(x){
add(s2,tr[x].sum);
Mul(x,s1);
return x;
}
else{
add(s1,tr[y].sum);
Mul(y,s2);
return y;
}
}
else if(l==r){
int now=New();
int a=tr[x].sum,b=tr[y].sum;
add(s1,b);
tr[now].sum=(s1*a+s2*b)%mod;;
add(s2,a);
return now;
}
pushdown(x);pushdown(y);
int now=New();
tr[now].ls=merge(tr[x].ls,tr[y].ls,l,mid);
tr[now].rs=merge(tr[x].rs,tr[y].rs,mid+1,r);
pushup(now);
return now;
}
然后这道题就做完啦。
时空复杂度 O ( n log n ) O(n\log n) O(nlogn),期望得分 100 分。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("ok\n")
inline ll read(){
ll x(0),f(1);char c=getchar();
while(!isdigit(c)) {
if(c=='-')f=-1;c=getchar();}
while(isdigit(c)) {
x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=5e5+100;
const int inf=1e9+100;
const int mod=998244353;
const bool Flag=0;
#define add(x,y) (((x)+=(y))>=mod&&((x)-=mod))
int n,m;
#define mid ((l+r)>>1)
struct node{
int ls,rs;
ll sum,mul=1;
}tr[N*40];
int tot;
vector<int>e[N];
inline int New(){
tr[++tot].mul=1;
return tot;
}
inline void Mul(int x,int w){
if(x){
tr[x].sum=tr[x].sum*w%mod;
tr[x].mul=tr[x].mul*w%mod;
}
return;
}
inline void pushdown(int x){
if(tr[x].mul!=1){
Mul(tr[x].ls,tr[x].mul);
Mul(tr[x].rs,tr[x].mul);
tr[x].mul=1;
}
return;
}
inline void pushup(int k){
tr[k].sum=(tr[tr[k].ls].sum+tr[tr[k].rs].sum)%mod;
}
ll ask(int k,int l,int r,int x,int y){
if(!k) return 0;
if(x<=l&&r<=y) return tr[k].sum;
pushdown(k);
ll res(0);
if(x<=mid) add(res,ask(tr[k].ls,l,mid,x,y));
if(y>mid) add(res,ask(tr[k].rs,mid+1,r,x,y));
return res;
}
ll s1,s2;
int merge(int x,int y,int l,int r){
//if(l>lim) return 0;
if(!x&&!y) return 0;
else if(!x||!y){
if(x){
add(s2,tr[x].sum);
Mul(x,s1);
return x;
}
else{
add(s1,tr[y].sum);
Mul(y,s2);
//printf("(%d %d) s2=%lld sum=%lld\n",l,r,s2,tr[y].sum);
return y;
}
}
else if(l==r){
int now=New();
int a=tr[x].sum,b=tr[y].sum;
add(s1,b);
tr[now].sum=(s1*a+s2*b)%mod;;
add(s2,a);
return now;
}
pushdown(x);pushdown(y);
int now=New();
tr[now].ls=merge(tr[x].ls,tr[y].ls,l,mid);
tr[now].rs=merge(tr[x].rs,tr[y].rs,mid+1,r);
pushup(now);
return now;
}
void ins(int &k,int l,int r,int p){
if(!k) k=New();
if(l==r){
tr[k].sum++;
return;
}
pushdown(k);
if(p<=mid) ins(tr[k].ls,l,mid,p);
else ins(tr[k].rs,mid+1,r,p);
pushup(k);
}
void print(int k,int l,int r){
if(!k) return;
if(l==r){
printf("d=%d dp=%lld\n",l,tr[k].sum);
return;
}
pushdown(k);
print(tr[k].ls,l,mid);
print(tr[k].rs,mid+1,r);
return;
}
int rt[N];
int dep[N],d[N];
void init(int x,int fa){
dep[x]=dep[fa]+1;
for(int to:e[x]){
if(to==fa) continue;
init(to,x);
}
return;
}
void dfs(int x,int fa){
for(int to:e[x]){
if(to==fa) continue;
dfs(to,x);
}
ins(rt[x],0,n,d[x]);
for(int to:e[x]){
if(to==fa) continue;
s1=ask(rt[to],0,n,0,dep[x]);
s2=0;
rt[x]=merge(rt[x],rt[to],0,n);
//printf("----------%d->%d\n",x,to);
//print(rt[x],0,n);
//puts("");
}
return;
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
n=read();
for(int i=1;i<n;i++){
int x=read(),y=read();
e[x].push_back(y);
e[y].push_back(x);
}
init(1,0);
m=read();
for(int i=1;i<=m;i++){
int u=read(),v=read();
d[v]=max(d[v],dep[u]);
}
dfs(1,0);
printf("%lld\n",ask(rt[1],0,n,0,0));
return 0;
}
边栏推荐
- Applet Custom Grid
- laravel Carbon 时间处理类使用
- [无线通信基础-15]:图解移动通信技术与应用发展-3- 数字通信2G GSM、CDMA、3G WDCMA/CDMA200/TD-SCDMA、4G LTE、5G NR概述
- QT web 开发 - video -- 笔记
- TypeError: can‘t convert cuda:0 device type tensor to numpy. Use Tensor. cpu() to copy the tensor to
- 关于白盒测试,这些技巧你得游刃有余~
- 工作6年,来盘点一下职场人混迹职场的黄金法则
- Handsontable數據網格組件
- 数学知识:满足条件的01序列—求组合数
- 【agora】用户管理
猜你喜欢
For the sustainable development of software testing, we must learn to knock code?
亲测有效,快速创建JMeter桌面快捷方式
工作6年,来盘点一下职场人混迹职场的黄金法则
数据探索电商平台用户行为流失分析
Lecun, a Turing Award winner, pointed out that the future of AI lies in self-learning, and the company has embarked on the journey
[problem handled] -nvidia SMI command cannot obtain the GPU process number of its own container and the external GPU process number
45 year old programmer tells you: why do programmers want to change jobs? It's too true
医疗HIS行业短信发送解决方案
Connectivity basis of Graphs
农产品换房?“变相”购房补贴!
随机推荐
测试必备工具—Postman实战教程
[fundamentals of wireless communication-14]: illustrated mobile communication technology and application development-2-the first generation mobile analog communication big brother
Log logrus third party library usage
Sécurité et santé microbiennes, qu'est - ce que le traitement biologique?
mysql插入\更新前+判断条件
PHP crawls data through third-party plug-ins
Laravel+redis generates an order number - automatically increase from 1 on the same day
如何选择券商?另外,手机开户安全么?
The argument type 'function' can't be assigned to the parameter type 'void function()‘
Ks009 implementation of pet management system based on SSH
7-2 拼题A打卡奖励 dp
[problem handled] -nvidia SMI command cannot obtain the GPU process number of its own container and the external GPU process number
1175. Prime Arrangements
PHP通过第三方插件爬取数据
【JS给元素添加属性:setAttribute;classList.remove;classList.add;】
go导入自建包
Thinking brought by strictmode -strictmode principle (5)
Batch import of Excel data in applet
QT web 开发 - video -- 笔记
Open3d point cloud bounding box