题解:P17859 「GLR-R5」白露 / ros
先考虑一下朴素的 dp。假设当前合法序列的最大值、严格次大值分别是
- 如果
x\ge mx_1 ,那么一定合法。 - 如果
x 是mx_1 的邻居并且x\ge mx_2 ,那么一定合法。 - 否则就需要满足
x 同时是mx_1,mx_2 的邻居,显然这样的x 只会有一个,并且满足剩下所有点的约束要求。
于是就可以设计出来一个朴素的 dp。定义
考虑优化上面的状态设计。显然这个
所以定义
先考虑下一个点选择的是
再考虑下一个邻居选择“公共邻居”的方案。设这个公共邻居是
再考虑选择一个新的严格次大值的情况。假设选定的是
在这种情况下,最大值与次大值在树上的距离变成了
最后一种就是选择一个新的最大值。为了方便转移,我们再定义一个数组
假设加入的新的最大值是
其中
在这个新的状态中,
这样下来,预处理部分需要二分找位置,所以复杂度是
::::info[代码]
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5,mod=1e9+9;
int T,n,m,sum[N],presum[N],st[N],tot,est[N],ast[N],etot,atot;
int f[2][N<<1],g[2][N<<1],h[2][N<<1],ok[N],pos[N],val[N<<1];
vector<int>adj[N],son[N];
struct Query{int mx,cnt,pos,id,l,r;};vector<Query>qry;
inline int getk(int u,int x){
int l=0,r=(int)son[u].size()-1,ans=-1;
while(l<=r){int mid=(l+r)>>1;if(son[u][mid]>=x)l=mid+1,ans=mid;else r=mid-1;}
return ans+1;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>T;while(T--){
cin>>n>>m;qry.clear();for(int i=1;i<=n;i++)adj[i].clear(),son[i].clear();
for(int i=1;i<n;i++){int u,v;cin>>u>>v;adj[u].push_back(v),adj[v].push_back(u);}
for(int u=1;u<=n;u++)sort(adj[u].begin(),adj[u].end());
for(int u=1;u<=n;u++){
for(auto v:adj[u])if(v<u)son[u].push_back(v);
sort(son[u].begin(),son[u].end(),greater<int>());
}
tot=etot=atot=0;
for(int u=1;u<=n;u++){
st[u]=tot,tot+=son[u].size()+1;
est[u]=etot,etot+=son[u].size();
ast[u]=atot,atot+=adj[u].size();
}
fill(f[0],f[0]+tot,0),fill(g[0],g[0]+tot,0),fill(h[0],h[0]+tot,0);
for(int u=1;u<=n;u++){
for(int j=0;j<(int)son[u].size();j++)pos[est[u]+j]=lower_bound(adj[son[u][j]].begin(),adj[son[u][j]].end(),u)-adj[son[u][j]].begin();
f[0][st[u]+son[u].size()]=1;
}
vector<int>ls;
for(int x=1;x<=n;x++){
for(int j=0;j<(int)son[x].size();j++){
int c=son[x][j];ls.clear();
if(adj[c].size()<=j+1){
int las=-1;
for(auto u:adj[c])if(c<u&&u<x){
int k=getk(x,u);
if(k!=las)ls.push_back(k),las=k;
}
}else for(int k=0;k<=j;k++)ls.push_back(k);
for(auto k:ls){
int L=son[x][k]+1,R=k==0?x-1:son[x][k-1];
L=max(L,c+1);if(L>R)continue;
int l=lower_bound(adj[c].begin(),adj[c].end(),L)-adj[c].begin();
int r=upper_bound(adj[c].begin(),adj[c].end(),R)-adj[c].begin();
if(l<r)qry.push_back({x,k,j,c,l,r});
}
}
}
cout<<n<<' ';int tms=m-1,cur=0;
while(tms--){
int nxt=cur^1;
for(int u=1;u<=n;u++){
int d=son[u].size(),now=0;
for(int k=d;k>=0;k--){
int p=st[u]+k;
now+=f[cur][p];if(now>=mod)now-=mod;
f[nxt][p]=f[cur][p]+g[cur][p];if(f[nxt][p]>=mod)f[nxt][p]-=mod;
g[nxt][p]=g[cur][p]+g[cur][p];if(g[nxt][p]>=mod)g[nxt][p]-=mod;
if(k){
ok[est[u]+k-1]=now+h[cur][p-1];if(ok[est[u]+k-1]>=mod)ok[est[u]+k-1]-=mod;
h[nxt][p-1]=h[cur][p-1]+h[cur][p-1];if(h[nxt][p-1]>=mod)h[nxt][p-1]-=mod;
f[nxt][p]+=now;if(f[nxt][p]>=mod)f[nxt][p]-=mod;
}
}
sum[u]=now;
}
presum[0]=0;
for(int u=1;u<=n;u++){
presum[u]=presum[u-1]+sum[u];
if(presum[u]>=mod)presum[u]-=mod;
}
for(int x=1;x<=n;x++){
for(int k=0;k<=(int)son[x].size();k++){
int l=k==(int)son[x].size()?1:son[x][k]+1,r=k==0?x-1:son[x][k-1];
if(l<=r){
int v=presum[r]-presum[l-1];if(v<0)v+=mod;
f[nxt][st[x]+k]+=v;if(f[nxt][st[x]+k]>=mod)f[nxt][st[x]+k]-=mod;
}
}
}
fill(val,val+atot,0);
for(int u=1;u<=n;u++)for(int j=0;j<(int)son[u].size();j++)val[ast[son[u][j]]+pos[est[u]+j]]=ok[est[u]+j];
for(int c=1;c<=n;c++){
int now=0;
for(int j=0;j<(int)adj[c].size();j++){
now+=val[ast[c]+j];if(now>=mod)now-=mod;
val[ast[c]+j]=now;
}
}
for(auto [mx,cnt,p,id,l,r]:qry){
int v=val[ast[id]+r-1];
if(l)v-=val[ast[id]+l-1];
if(v<0)v+=mod;
g[nxt][st[mx]+cnt]+=v;if(g[nxt][st[mx]+cnt]>=mod)g[nxt][st[mx]+cnt]-=mod;
h[nxt][st[mx]+p]+=v;if(h[nxt][st[mx]+p]>=mod)h[nxt][st[mx]+p]-=mod;
}
cur=nxt;int ans=0;
for(int i=0;i<tot;i++){ans+=f[cur][i];if(ans>=mod)ans-=mod;}
cout<<ans<<' ';
}cout<<'\n';
}
return 0;
}
::::