ATR175D LIS on Tree II 学习笔记
ATR175D LIS on Tree II 学习笔记
题意简述
给定一棵 \(n\) 个结点,以 \(1\) 为根的树。需要给每个点 \(i\) 赋一个 \(w_i\in [1,n]\),且满足 \(\forall i\neq j,w_i\neq w_j\)。
定义一个结点的得分 \(p_i=\text{LIS}(1\to i)\)。试给出一种赋值方案使 \(\sum_{i=1}^n p_i=m\),或报告无解。
\(n\le 2\times 10^5,m\le 10^{11}\)。
做法解析
判无解是很容易的。问题有解当且仅当 \(m\in [n,\sum \text{dep}(u)]\)(其中 \(\text{dep}(1)=1\))。
有至少一半的构造题都是可以构造出方案,取到上下界间的任意值的。这题我们也来思考如何稳定构造出解。
我们尝试分析填数时每个数会带来的贡献。LIS这种从一个前缀一步步扩展而来的问题,应当适合从根往下地分析。
令点 \(u\) 的父亲为 \(fa\)。若 \(w_u>\max_{i\in [1\to fa]} w_i\),则 \(w_u\) 子树内所有结点的答案都将加一,否则子树内所有结点的答案则不增不减。这类似于一个背包问题,每个结点相当于一个价值为 \(siz_u\) 的物品,我们最后要选出总价值为 \(m\) 的东西。
容易发现能够选出的总价值 \(\sum v\in [0,\sum siz]\)。
这里证明一下:
我们知道,往一个能用子集和恰好表示出 \([0,r]\) 里面加一个元素 \(x\),那么新的集合能用子集和表示出的区间就是 \([0,r]\cup[x,n+x]\),新区间仍然连续当且仅当 \(x\le r+1\)。此结论在LGP4587中亦有记载。
我们先考虑儿子后考虑父亲地将 \(siz_u\) 一个一个加到集合 \(S\) 里面。第一个加的一定是一个叶子结点,子集和可表示值域区间从 \([0,0]\) 变为 \([0,1]\)。之后我们发现,加叶子结点一定不破坏可表示值域区间的连续性,而加一个非叶子结点 \(u\) 时,一定已经有 \(siz_u-1\) 个结点被添加,也就是说此时必然有 \(r\ge siz_u-1\),也即 \(siz_u\le r+1\)。所以我们归纳地证明了我们一定可以构造出来。
另外,由LIS的意义可知根结点要视为是必选的。所以到这里我们也从另一种视角证明了上述的上下界。
然后我们具体怎么凑出 \(m\) 呢?正着做不太好做,但反着做容易很多,我们先默认所有结点都选上,然后再从根往下一层一层地考虑,每层里面价值从大到小地,如果删掉当前结点的贡献后总和仍然大于等于 \(m\) 就删除之。
这么做是对的,原因是我们从粗粒度物往细粒度物考虑一定更优,而且这题的粗粒度物总是可表示为若干细粒度物之和。
好了我们已经确定哪些点要造成贡献了,怎么构造答案呢?这一步实则不难。
为了保证没取到的点不造成贡献,我们令所有没取到的点的权值都小于所有取到的点的权值。为了保证没取到的点不会自己形成一段LIS,我们让所有没取到的点的权值都从根往下降序排列就行。同理,既然取到的点要形成LIS,那么这些点的权值就应该从根往下升序排列。
时间复杂度 \(O(n\log n)\),瓶颈在排序上。
代码实现
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=2e5+5;
int N,X,Y;lolo M,sum;
vector<int> Tr[MaxN];
void addudge(int u,int v){
Tr[u].push_back(v);
Tr[v].push_back(u);
}
int siz[MaxN];pii P[MaxN];
void dfs1(int u,int f){
siz[u]=1;
for(int v : Tr[u]){
if(v==f)continue;
dfs1(v,u),siz[u]+=siz[v];
}
P[u]={-siz[u],u},sum+=siz[u];
}
int vis[MaxN],A[MaxN],tot;
void dfs2(int u,int f){
for(int v : Tr[u])if(v!=f)dfs2(v,u);
if(!vis[u])A[u]=++tot;
}
void dfs3(int u,int f){
if(vis[u])A[u]=++tot;
for(int v : Tr[u])if(v!=f)dfs3(v,u);
}
int main(){
readis(N,M);
for(int i=1;i<N;i++)readis(X,Y),addudge(X,Y);
dfs1(1,0);if(M<N||M>sum){puts("No");return 0;}
puts("Yes"),sort(P+1,P+N+1);
for(int i=1;i<=N;i++){
auto &[fi,se]=P[i];
if(M+fi>=0)vis[se]=1,M+=fi;
}
dfs2(1,0),dfs3(1,0);
for(int i=1;i<=N;i++)writip(A[i]);
return 0;
}
浙公网安备 33010602011771号