【NOIP 2015 DAY2 T3】 运输计划 (树链剖分-LCA)
题目背景
公元 2044 年,人类进入了宇宙纪元。
题目描述
L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球。
小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物
流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之 间不会产生任何干扰。
为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。
在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后, 这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的 物流公司的阶段性工作就完成了。
如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段 性工作所需要的最短时间是多少?
输入输出格式
输入格式:
输入文件名为 transport.in。
第一行包括两个正整数 n、m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。
接下来 n-1 行描述航道的建设情况,其中第 i 行包含三个整数 ai, bi 和 ti,表示第
i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。
接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j个 运输计划是从 uj 号星球飞往 vj 号星球。
输出格式:
输出 共1行,包含1个整数,表示小P的物流公司完成阶段性工作所需要的最短时间。
输入输出样例
输入样例#1:
6 3 1 2 3 1 6 4 3 1 7 4 3 6 3 5 5 3 6 2 5 4 5输出样例#1:
11说明
所有测试数据的范围和特点如下表所示
请注意常数因子带来的程序效率上的影响。
【分析】
这题,像是很多解法哦。
首先是,你是选大的那几条链删掉公共边,就是树链的交,然后维护一个最大值【可是我不会树链的交【如果没有交链直接break就好了
我打的是二分版本。
先预处理每条路径的LCA,二分答案,如果某条路径的长度大于这个二分答案,那么意味着他里面一定要割掉一条边嘛,
那么,把这样的路径记录下来(那个,是一个很妙的方法,在x,y上标记1,在lca上标记-2,子树的sum就是它的访问次数,我们判断的时候只需要dfs一遍,回溯累加就好了)
我们只能选择涵盖所有不合法路径的边减掉,取他们之中的max当然是更好的,然后看看这个max能不能使路径合法。
【为什么我打的nlogxx比别人的暴力还慢【捂脸= =
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #include<cmath> 8 using namespace std; 9 #define Maxn 300010 10 #define LL long long 11 12 struct node 13 { 14 int x,y,c,next; 15 }t[Maxn*2];int len; 16 17 int n,m; 18 19 int first[Maxn]; 20 int ax[Maxn],ay[Maxn],lca[Maxn]; 21 LL h[Maxn],ln[Maxn]; 22 23 void ins(int x,int y,int c) 24 { 25 t[++len].x=x;t[len].y=y;t[len].c=c; 26 t[len].next=first[x];first[x]=len; 27 } 28 29 LL mymax(LL x,LL y) {return x>y?x:y;} 30 31 int dep[Maxn],dfn[Maxn],sm[Maxn],son[Maxn]; 32 int fa[Maxn],w[Maxn]; 33 void dfs1(int x,int f) 34 { 35 dep[x]=dep[f]+1;sm[x]=1;son[x]=0; 36 fa[x]=f; 37 for(int i=first[x];i;i=t[i].next) if(t[i].y!=f) 38 { 39 int y=t[i].y; 40 w[y]=t[i].c; 41 dfs1(y,x); 42 sm[x]+=sm[y]; 43 if(sm[y]>sm[son[x]]) son[x]=y; 44 } 45 } 46 47 int tp[Maxn],cnt=0; 48 void dfs2(int x,int tpp) 49 { 50 dfn[x]=++cnt;h[cnt]=h[cnt-1]+w[x]; 51 tp[x]=tpp; 52 if(son[x]) dfs2(son[x],tpp); 53 for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x]&&t[i].y!=son[x]) 54 { 55 int y=t[i].y; 56 dfs2(y,y); 57 } 58 } 59 60 void ffind(int id,int x,int y) 61 { 62 int tt; 63 while(tp[x]!=tp[y]) 64 { 65 if(dep[tp[x]]<dep[tp[y]]) tt=x,x=y,y=tt; 66 ln[id]+=h[dfn[x]]-h[dfn[tp[x]]-1]; 67 x=fa[tp[x]]; 68 } 69 if(dep[x]<dep[y]) tt=x,x=y,y=tt; 70 ln[id]+=h[dfn[x]]-h[dfn[y]]; 71 lca[id]=y; 72 } 73 74 int tot[Maxn]; 75 76 int les(int x,int tt) 77 { 78 int ans=-1; 79 for(int i=first[x];i;i=t[i].next) if(t[i].y!=fa[x]) 80 { 81 int y=t[i].y; 82 int now=les(y,tt); 83 tot[x]+=tot[y]; 84 if(now!=-1) ans=mymax(ans,now); 85 } 86 if(tot[x]==tt) ans=mymax(ans,w[x]); 87 return ans; 88 } 89 90 bool check(LL mid) 91 { 92 memset(tot,0,sizeof(tot)); 93 LL mx=0;int tt=0; 94 for(int i=1;i<=m;i++) if(ln[i]>mid) 95 { 96 tot[ax[i]]++;tot[ay[i]]++; 97 tot[lca[i]]-=2; 98 mx=mymax(mx,ln[i]); 99 tt++; 100 } 101 int now=les(1,tt); 102 if(now==-1||mx-now>mid) return 0; 103 return 1; 104 } 105 106 void get_ans(LL l,LL r) 107 { 108 while(l<r) 109 { 110 LL mid=(l+r)/2; 111 if(check(mid)) r=mid; 112 else l=mid+1; 113 } 114 printf("%lld\n",l); 115 } 116 117 int main() 118 { 119 LL mx=0; 120 scanf("%d%d",&n,&m); 121 len=0; 122 memset(first,0,sizeof(first)); 123 for(int i=1;i<n;i++) 124 { 125 int x,y,c; 126 scanf("%d%d%d",&x,&y,&c); 127 ins(x,y,c);ins(y,x,c); 128 } 129 dep[0]=0; 130 dfs1(1,0);h[0]=0; 131 dfs2(1,1); 132 for(int i=1;i<=m;i++) 133 { 134 scanf("%d%d",&ax[i],&ay[i]); 135 ffind(i,ax[i],ay[i]); 136 mx=mymax(mx,ln[i]); 137 } 138 get_ans(0,mx); 139 return 0; 140 }
2016-11-15 16:41:22