树上的路径

 树上的路径

题目描述

给定一棵N个结点的树,结点用正整数1..N编号,每条边有一个正整数权值。用d(a,b)表示从结点a到结点b路径上经过边的权值和,其中要求a<b。将这N*(N-1)/2个距离值从大到小排序,输出前M个距离值。


Sol

 

今天见识了一种高级东东:点分治序。
就是每次点分dfs是,同时记一个dfs序,一个点可以对应多个不同的dfs序。
考虑原先点分合并时是一棵棵子树合并上去,现在改成一个点对应一段dfs序的区间,表示这个点的链可以和这个区间合并。
然后我们把点和区间放进堆里,每次取堆顶,并把堆顶分裂成两个区间。
这个东西似乎很厉害。
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #define maxn 50005
 9 using namespace std;
10 int n,m,head[maxn],tot;
11 int siz,f[maxn],sc,rt,vis[maxn],sz[maxn],st[maxn*20][22],w[maxn*20];
12 int L[maxn*20];
13 struct node{
14     int v,nex,w;
15 }e[maxn*2];
16 struct no{
17     int l,r,x,v;
18 };
19 bool operator <(no a,no b){
20     return a.v<b.v;
21 }
22 priority_queue<no>q;
23 void add(int t1,int t2,int t3){
24     e[++tot].v=t2;e[tot].w=t3;e[tot].nex=head[t1];head[t1]=tot;
25 }
26 void findr(int k,int fa){
27     f[k]=0;sz[k]=1;
28     for(int i=head[k];i;i=e[i].nex){
29         if(e[i].v==fa||vis[e[i].v])continue;
30         findr(e[i].v,k);
31         sz[k]+=sz[e[i].v];
32         f[k]=max(f[k],sz[e[i].v]);
33     }
34     f[k]=max(f[k],siz-sz[k]);
35     if(f[k]<f[rt])rt=k;
36 }
37 int dfs(int k,int fa,int W,int l,int r,int wm){
38     sc++;w[sc]=W;st[sc][0]=sc;sz[k]=1;
39     if(l<=r)q.push((no){l,r,sc,W+wm}); 
40     int M=W;
41     for(int i=head[k];i;i=e[i].nex){
42         if(e[i].v==fa||vis[e[i].v])continue;
43         M=max(M,dfs(e[i].v,k,W+e[i].w,l,r,wm));
44         sz[k]+=sz[e[i].v];
45     }
46     return M;
47 }
48 void work(int k){
49     vis[k]=1;int la=sc+1,lw=0;
50     for(int i=head[k];i;i=e[i].nex){
51         if(vis[e[i].v])continue;
52         int W=dfs(e[i].v,k,e[i].w,la,sc,lw);
53         lw=max(lw,W);
54     }
55     sc++;w[sc]=0;st[sc][0]=sc;
56     if(la<sc)q.push((no){la,sc-1,sc,lw});
57     for(int i=head[k];i;i=e[i].nex){
58         if(vis[e[i].v])continue;
59         rt=0;siz=sz[e[i].v];findr(e[i].v,k);
60         work(rt);
61     }
62 }
63 int ask(int l,int r){
64     int t=L[r-l+1];
65     int a=st[l][t],b=st[r-(1<<t)+1][t];
66     return w[a]>w[b]?a:b;
67 }
68 int main()
69 {
70     cin>>n>>m;
71     for(int i=1,t1,t2,t3;i<n;i++){
72         scanf("%d%d%d",&t1,&t2,&t3);
73         add(t1,t2,t3);add(t2,t1,t3);
74     }
75     rt=0;f[0]=1e9;siz=n;findr(1,0);
76     work(rt);
77     for(int j=1;j<=20;j++)
78     for(int i=1;i+(1<<j)-1<=sc;i++){
79         int a=st[i][j-1],b=st[i+(1<<j-1)][j-1];
80         st[i][j]=(w[a]>w[b])?a:b;
81     }
82     for(int i=2;i<=sc;i++)L[i]=L[i/2]+1;
83     while(m--){
84         no t=q.top();q.pop();
85         printf("%d\n",t.v);
86         int p=ask(t.l,t.r);
87         if(p>t.l)q.push((no){t.l,p-1,t.x,w[t.x]+w[ask(t.l,p-1)]});
88         if(p<t.r)q.push((no){p+1,t.r,t.x,w[t.x]+w[ask(p+1,t.r)]});
89     }
90     return 0;
91 }
View Code

 

posted @ 2019-04-10 07:18  liankewei123456  阅读(211)  评论(0编辑  收藏  举报