树上的路径
2015-11-15 10:10
281 查看
树上的路径
时间限制: 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 1050000000 using namespace std; int n,m,cnt,size ,w ,fa ,dis ,s[N*17],c[N*17]; int k,la ,ff[N*2],q ,flag ,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; }
相关文章推荐
- C#第十三天
- mysql使用笔记:相关术语和定义
- Servlet实现文件上传,可多文件上传
- Day7
- 仿百度首页并实现搜索功能
- 原来软件工程可以这样学~~~
- JavaBean操作技术之二:BeanUtils框架
- iOS中的图片格式
- Java开发基本DOS命令了解
- mysql子查询
- 【译】前端开发者都应知道的 jQuery 小技巧
- C++11实现模板化(通用化)RAII机制
- 从零学Android(八)、Android资源类型之Drawable资源
- linux网络编程
- ABAP BDC 可输入不同事务码的通用BDC
- ios中的库
- 【最新】iOS App上架AppStore 教程 (Part 三)
- Reachability 苹果官方提供的第三方库 (判断联网状态)
- gridView里如何添加详情按钮,点击它可以转到另一页,以获取该行的详细信息。
- Add Two Numbers