题目
给定一棵N个结点的树,结点用正整数1..N编号,每条边有一个正整数权值。用d(a,b)表示从结点a到结点b路径上经过边的权值和,其中要求 a<b a < b 。将这N*(N-1)/2个距离值从大到小排序,输出前M个距离值。
解题思路
点分治,对于点分治子树x中的每个点y,维护2个值,一个是x到y的距离d(x,y),一个是x的其他子树的点w到y的祖先,x的儿子z的距离的最大值d(w,z)max。
其中求dis(w,z)max,用st表维护一下就好了。
要求
a<b
a
<
b
?
在点分治序列中,求最大值的范围本来是有2段的,现在只需要求点分治序较前的那段就好了。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#define N 50010
#define M 1000010
#define P(a) putchar(a)
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct note1{int l,r;};note1 p[M];
struct no_ed{int to,next,val;}edge[N<<1];
struct use{int l,r,ax,m;}ttt,t11;
int tot,head[N];
int i,j,k,l,r,n,m,ans,Sz;
int u,v,w;
int sd[M],id,mx[N],siz[N],hv;
int f[20][M],dis[N];
bool vis[N];
priority_queue<use>qu;
bool operator<(use a,use b){return sd[a.ax]+sd[a.m]<sd[b.ax]+sd[b.m];}
int read(){
int rs=0,fh=1;char ch;
while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
return fh*rs;
}
void write(int x){
if(x>9)write(x/10);
P(x%10+'0');
}
void lb(int x,int y,int z){
edge[++tot].to=y;
edge[tot].next=head[x];
edge[tot].val=z;
head[x]=tot;
}
int Max(int x,int y){return x>y?x:y;}
void find(int x,int y){
int i;
siz[x]=1;mx[x]=0;
for(i=head[x];i;i=edge[i].next)
if((edge[i].to^y)&&!vis[edge[i].to]){
find(edge[i].to,x);
siz[x]+=siz[edge[i].to];
mx[x]=Max(mx[x],siz[edge[i].to]);
}
mx[x]=Max(mx[x],Sz-siz[x]);
if(mx[hv]>mx[x])hv=x;
}
void getdis(int x,int y){
int i;
sd[++id]=dis[x];p[id].l=l;p[id].r=r;
for(i=head[x];i;i=edge[i].next)
if((edge[i].to^y)&&(!vis[edge[i].to])){
dis[edge[i].to]=dis[x]+edge[i].val;
getdis(edge[i].to,x);
}
}
void dg(int x){
vis[x]=1;sd[++id]=0;
p[id].l=p[id].r=0;l=r=id;
int i;
for(i=head[x];i;i=edge[i].next)if(!vis[edge[i].to]){
dis[edge[i].to]=edge[i].val;
getdis(edge[i].to,x);
r=id;
}
for(i=head[x];i;i=edge[i].next)if(!vis[edge[i].to]){
hv=0;
Sz=siz[edge[i].to];
find(edge[i].to,0);
dg(hv);
}
}
int query(int l,int r){
int k=log(r-l+1.0)/log(2.0);
return sd[f[k][l]]>sd[f[k][r-(1<<k)+1]]?f[k][l]:f[k][r-(1<<k)+1];
}
void prepare(){
int i,j;
fo(i,1,id)f[0][i]=i;
fo(i,1,19)
fo(j,1,id)if(j+(1<<i)-1<=id){
if(sd[f[i-1][j]]>sd[f[i-1][j+(1<<(i-1))]]){
f[i][j]=f[i-1][j];
}else f[i][j]=f[i-1][j+(1<<(i-1))];
}else break;
fo(i,1,id)if(p[i].l){
ttt.l=p[i].l;ttt.r=p[i].r;ttt.ax=i;ttt.m=query(p[i].l,p[i].r);
qu.push(ttt);
}
}
int main(){
n=read();m=read();
fo(i,1,n-1){
u=read();v=read();w=read();
lb(u,v,w);lb(v,u,w);
}
mx[0]=2147483647;
hv=0;Sz=n;
find(1,0);
dg(hv);
prepare();
while(m--){
t11=qu.top();
qu.pop();
write(sd[t11.ax]+sd[t11.m]);P('\n');
if(t11.l<=t11.m-1){
ttt.l=t11.l;ttt.r=t11.m-1;ttt.ax=t11.ax;
ttt.m=query(t11.l,t11.m-1);
qu.push(ttt);
}
if(t11.m+1<=t11.r){
ttt.l=t11.m+1;ttt.r=t11.r;ttt.ax=t11.ax;
ttt.m=query(t11.m+1,t11.r);
qu.push(ttt);
}
}
return 0;
}