JZOJ 3329. 【NOI2013模拟】树上的路径

题目

给定一棵N个结点的树,结点用正整数1..N编号,每条边有一个正整数权值。用d(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
在点分治序列中,求最大值的范围本来是有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;
}

猜你喜欢

转载自blog.csdn.net/huangjingyuan107/article/details/81074444
今日推荐