树上的路径

来源:互联网 发布:如何改变图片尺寸软件 编辑:程序博客网 时间:2024/03/29 14:55

树上的路径

时间限制: 1 Sec 内存限制: 256 MB
题目描述
给定一棵N个结点的树,结点用正整数1..N编号,每条边有一个正整数权值。用d(a,b)表示从结点a到结点b路径上经过边的权值和,其中要求a

题解

类似于noi2009超级钢琴的做法,先用点分治找出每个点能和它联通的点的区间,然后把这些东西扔到一个堆里,用主席树维护区间第K大即可。

代码

#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<cmath> #include<queue>#include<algorithm> #define N 50010#define inf 1050000000using namespace std;int n,m,cnt,size[N],w[N],fa[N],dis[N],s[N*17],c[N*17];int k,la[N],ff[N*2],q[N],flag[N],st,maxn,tot;struct node{int a,b,c;}map[N*2];struct wbs{  int l,r,pos,num1,num2;  bool operator<(const wbs &cyc)  const{return num1+num2<cyc.num1+cyc.num2;}};struct point{int lc,rc,size;}t[N*270];priority_queue<wbs>h;void add(int a,int b,int c){  map[++k]=(node){a,b,c};ff[k]=la[a];la[a]=k;  map[++k]=(node){b,a,c};ff[k]=la[b];la[b]=k;}int find(int S){  int l=1,r=2,num=inf,res;q[1]=S;flag[S]=1;fa[S]=0;  while(l<r)  {    int x=q[l];l++;size[x]=1;w[x]=0;    for(int a=la[x];a;a=ff[a])      if(!flag[map[a].b])        q[r]=map[a].b,flag[q[r]]=1,fa[q[r]]=x,r++;    }  if(r==2)return -1;  for(int i=r-1;i;i--)  {    int x=q[i];flag[x]=0;    if(fa[x])size[fa[x]]+=size[x],w[fa[x]]=max(w[fa[x]],size[x]);    if(max(w[x],r-size[x]-1)<num)num=max(w[x],r-size[x]-1),res=x;  }  return res;}void work(int S,int top,int num){  int l=1,r=2,end=cnt,tmp=0;  q[1]=S;dis[S]=num;flag[S]=1;  while(l<r)  {     int x=q[l];l++;s[++cnt]=dis[x];tmp=max(tmp,dis[x]);    for(int a=la[x];a;a=ff[a])      if(!flag[map[a].b])        q[r]=map[a].b,flag[q[r]]=1,dis[q[r]]=dis[x]+map[a].c,r++;  }  for(int i=r-1;i;i--)  {    int x=q[i];flag[x]=0;    h.push((wbs){st,end,end-st+1,dis[x],maxn});  }  maxn=max(maxn,tmp);}void solve(int x){  int rt=find(x);  if(rt==-1)return;  flag[rt]=1;st=++cnt;maxn=0;s[cnt]=0;  for(int a=la[rt];a;a=ff[a])    if(!flag[map[a].b])work(map[a].b,rt,map[a].c);  for(int a=la[rt];a;a=ff[a])    if(!flag[map[a].b])solve(map[a].b);}class seg_tree{  public:  void modify(int x,int pre,int l,int r,int des)  {    t[x]=t[pre];t[x].size++;    if(l==r)return;    int mid=l+r>>1;    if(des<=mid)modify(t[x].lc=++tot,t[pre].lc,l,mid,des);    else modify(t[x].rc=++tot,t[pre].rc,mid+1,r,des);  }  int qry(int x,int pre,int l,int r,int des)  {    if(l==r)return c[l];    int mid=l+r>>1,num=t[t[x].lc].size-t[t[pre].lc].size;    if(des<=num)qry(t[x].lc,t[pre].lc,l,mid,des);    else qry(t[x].rc,t[pre].rc,mid+1,r,des-num);  }}T;int main(){  int a,b,v;  scanf("%d%d",&n,&m);  for(int i=1;i<n;i++)    scanf("%d%d%d",&a,&b,&v),add(a,b,v);  solve(1);  for(int i=1;i<=cnt;i++)c[i]=s[i];  sort(c+1,c+cnt+1);tot=cnt;  int Tnum=unique(c+1,c+cnt+1)-c-1;  for(int i=1;i<=cnt;i++)    T.modify(i,i-1,1,Tnum,lower_bound(c+1,c+Tnum+1,s[i])-c);  while(m--&&h.size())  {    wbs x=h.top();h.pop();    printf("%d\n",x.num1+x.num2);    if(x.pos==1)continue;    x.num2=T.qry(x.r,x.l-1,1,Tnum,--x.pos);    h.push(x);  }  return 0;}
0 0
原创粉丝点击