树上路径
来源:互联网 发布:pg数据库substring 编辑:程序博客网 时间:2024/04/25 21:34
题目描述
给出一棵树,求出最小的k,使得,且在树中存在路径p,使得k>=S且k<=E。(k为路径p上的边的权值和)
n<=10^5,|E-S|<=10^6,1<=Wi<=1000,|E|,|S|<=10^9
怎么看都是点剖。
而对k有两个限制,不能直接求最小值,但是可以求在这个区间范围内的k有多少个。
二分+点剖
二分E的值,求在这个区间范围内的k的数量,若>0则合法。
只有第一次点剖才排序,然后保存排序后的数值,这样复杂度为O(
代码
#include<cstring>#include<algorithm>#include<cstdio>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define ll long longusing namespace std;const int maxn=100000+100;int i,j,n,d[maxn],f[maxn],s[maxn],root,mid,ss,l,r,t,ro[maxn];ll ans;int q[maxn*50],st[maxn*50],en[maxn*50],tt;int k[maxn],g[maxn*2],next[maxn*2],c[maxn*2],num,cnt;int k1[maxn],g1[maxn*2],next1[maxn*2],b;bool bz[maxn];void add(int x,int y,int z){next[++num]=k[x];k[x]=num;g[num]=y;c[num]=z;}void add1(int x,int y){next1[++cnt]=k1[x];k1[x]=cnt;g1[cnt]=y;}void dfs(int x,int y){ s[x]=1,f[x]=0; int i=k[x]; while (i){ if ((!bz[g[i]])&&(g[i]!=y)) dfs(g[i],x),s[x]+=s[g[i]],f[x]=max(f[x],s[g[i]]); i=next[i]; } f[x]=max(f[x],f[0]-s[x]);if (f[x]<f[root]) root=x;}void df(int x,int y){ if (d[x]>mid) return; q[++num]=d[x]; int i=k[x]; while (i){ if ((!bz[g[i]])&&(g[i]!=y)) d[g[i]]=d[x]+c[i],df(g[i],x); i=next[i]; }}ll chu(int x){ tt++; if (st[tt]==0) { st[tt]=num+1,df(x,0),en[tt]=num; sort(q+st[tt],q+1+en[tt]); } int i,j1=en[tt],j=en[tt];ll w=0; fo(i,st[tt],en[tt]-1){ while (q[i]+q[j]>mid&&j>=i) j--;if (j<=i) break; if (j1==i) j1=i+1;else while ((q[i]+q[j1-1]>=ss)&&(j1-1>i)) j1--; if ((q[i]+q[j1]<ss)||(j<j1)) continue; w+=j-j1+1; } return w;}void fen(int x){ bz[x]=1,d[x]=0,b=0,ans+=chu(x);b=1; int i=k[x]; while (i){ if (!bz[g[i]]) add1(x,g[i]),ans-=chu(g[i]); i=next[i]; }i=k1[x]; while (i){ int go=g1[i]; f[root=0]=s[go],dfs(go,0),ro[++t]=root; fen(ro[t]); i=next1[i]; }}void fen1(int x){ if (ans) return; b=0,ans+=chu(x); int i=k1[x];b=1; while (i) { ans-=chu(g1[i]); i=next1[i]; } i=k1[x];while (i)fen1(ro[++t]),i=next1[i];}int main(){ scanf("%d%d%d",&n,&ss,&r);l=ss,mid=r; fo(i,1,n-1) {int x,y,z;scanf("%d%d%d",&x,&y,&z);add(x,y,z);add(y,x,z);} t=0;f[root=0]=n; dfs(1,0);ro[t]=root;num=tt=0; fen(root); if (ans==0) {printf("-1\n");return 0;} while (l<r){ mid=(l+r)/2,t=tt=ans=0,fen1(ro[t]); if (ans) r=mid;else l=mid+1; } printf("%d\n",l);}
0 0
- 树上路径
- 树上路径
- 树上路径
- noip2013truck树上路径倍增
- 树上的路径
- [bzoj3784]树上的路径
- 树上最长单色路径
- 树上最长单色路径
- 树上最长单色路径
- 3784: 树上的路径
- 【JZOJ 4715】 树上路径
- 【JZOJ4715】树上路径
- 【JZOJ 4715】树上路径
- 【NOIP提高】树上路径
- 树上最长单色路径
- [JZOJ5055]树上路径
- 5055. 树上路径
- GFOJ510树上路径
- Python读写文件
- 2014-11-12-自定义子弹
- 用 PNChart 做统计图
- Leetcode 167. Two Sum II - Input array is sorted (Medium) (cpp)
- 父类调用子类的成员变量
- 树上路径
- 根据前序遍历序列和中序遍历序列构造二叉树
- 记录一笔-直接插入排序
- Unity5的AssetBundle系统在mmo中的使用经验
- AlertDialog的简单实用
- Lambda表达式
- PAT甲级.1027. Colors in Mars (20)
- sdut oj2140 图结构练习——判断给定图是否存在合法拓扑序列
- 线程池函数1 - 异步调用函数