传送门:bzoj3784
题解
前 k k k大比较好做(之前看成前 k k k小了)
所有的最优前k步问题最终都转成了bzoj2006: [NOI2010]超级钢琴…
如何将序列上问题转到树上,并维护本质不同的拓展呢?
考虑点分治,把树上问题转回点分治序上的问题:
对于序列中的每个点
i
i
i,权值
v
i
=
d
i
s
(
v
i
,
i
的
分
治
重
心
)
v_i=dis(v_i,i的分治重心)
vi=dis(vi,i的分治重心),对于
i
i
i可与其组合的点
j
j
j满足:
- 属于同一个分治重心
-
i
,
j
i,j
i,j不在分治重心的某个子结点的同一子树内
这样的 j j j就是在点分治序上是连续的两段,由于 ( i , j ) , ( j , i ) (i,j),(j,i) (i,j),(j,i)等价,所以固定某个方向的一段即可。
在优先队列中维护这样的四元组 ( u , l , r , p ) (u,l,r,p) (u,l,r,p)表示点 u u u可选范围为 [ l , r ] [l,r] [l,r]且其中值最大的为 v p v_p vp,按 v i + v p v_i+v_p vi+vp降序排序。
拓展
(
u
,
l
,
r
,
p
)
→
(
u
,
l
,
p
−
1
,
m
a
x
(
l
,
p
−
1
)
)
,
(
u
,
p
+
1
,
r
,
m
a
x
(
p
+
1
,
r
)
)
(u,l,r,p)\to (u,l,p-1,max(l,p-1)),(u,p+1,r,max(p+1,r))
(u,l,r,p)→(u,l,p−1,max(l,p−1)),(u,p+1,r,max(p+1,r))
S
T
ST
ST表维护区间最大值。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=50010,M=1e6+10;
int n,m,d[M],mx[20][M],bel[M],brt[M],lg[M];
int head[N],to[N<<1],nxt[N<<1],w[N<<1],tot;
int df[N],ot[N],sz[N],dfn,S,MN,rt,nw;
bool vs[N];
inline int ask(int l,int r)
{
int bs=lg[r-l+1],x=mx[bs][l],y=mx[bs][r-(1<<bs)+1];
return d[x]>d[y]?x:y;
}
struct P{
int u,l,r,p,v;
P(){};
P(int u_,int l_,int r_){u=u_;l=l_;r=r_;p=ask(l,r);v=d[u]+d[p];};
bool operator <(const P&ky)const{return v<ky.v;}
}dg;
priority_queue<P>que;
inline void lk(int u,int v,int vv)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=vv;}
void fdrt(int x,int fr)
{
int i,j,mxx=0;sz[x]=1;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(j==fr || vs[j]) continue;
fdrt(j,x);sz[x]+=sz[j];
mxx=max(mxx,sz[j]);
}
mxx=max(mxx,S-sz[x]);
if(mxx<MN) MN=mxx,rt=x;
}
void dfs(int x,int fr,int dis)
{
int i,j;
d[(df[x]=++dfn)]=dis;
brt[dfn]=nw;mx[0][dfn]=dfn;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(j==fr || vs[j]) continue;
dfs(j,x,dis+w[i]);
}
ot[df[x]]=dfn;
}
void col(int x,int fr)
{
int i,j;bel[df[x]]=nw;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(j==fr || vs[j]) continue;
col(j,x);
}
}
void divide(int x)
{
int i,j,sum=S;vs[x]=true;
nw=dfn+1;dfs(x,0,0);
for(i=head[x];i;i=nxt[i]){
j=to[i];if(vs[j]) continue;
nw=df[j];col(j,x);
}
for(i=head[x];i;i=nxt[i]){
j=to[i];if(vs[j]) continue;
S=sz[j]<sz[x]?sz[j]:sum-sz[x];MN=N;
fdrt(j,x);divide(rt);
}
}
int main(){
int i,j,x,y,z;
scanf("%d%d",&n,&m);
for(i=1;i<n;++i){scanf("%d%d%d",&x,&y,&z);lk(x,y,z);lk(y,x,z);}
S=n;MN=N;fdrt(1,0);divide(rt);
for(i=2;i<=dfn;++i) lg[i]=lg[i>>1]+1;
for(j=1;(1<<j)<=dfn;++j)
for(i=1;i+(1<<j)-1<=dfn;++i){
x=mx[j-1][i];y=mx[j-1][i+(1<<(j-1))];
mx[j][i]= d[x]>d[y]?x:y;
}
for(i=1;i<=dfn;++i) if(bel[i]){
if(brt[i]<bel[i]) que.push(P(i,brt[i],bel[i]-1));
// if(ot[brt[i]]>ot[bel[i]]) que.push(P(i,ot[bel[i]]+1,ot[brt[i]]));
}
for(;m;--m){
dg=que.top();que.pop();printf("%d\n",dg.v);
if(dg.l<dg.p) que.push(P(dg.u,dg.l,dg.p-1));
if(dg.r>dg.p) que.push(P(dg.u,dg.p+1,dg.r));
}
return 0;
}