Vijos1983 NOIP2015Day2T3 运输计划 transport LCA
转载一个大佬的题解:
下面谈谈我的感悟:
当然写代码也是写的很艰辛:
我力劝C++的同胞们,这题卡常数,Dfs党会吃亏,比如这里这个UOJ的数据
我们可以使用Bfs和尽量避免写Dfs,不然会Tle的
以下代码实测极端数据约900ms,正所谓卡常数,如果把一开始的dfs改为bfs可能会更快……(博主很懒,不改了)
总结一下大佬的题解:
1. Dfs或Bfs构建树,然后记录下各种信息,现在主要是以下几点:
1)子节点 son[rt] vector <int>
2)深度 deep[rt] int
3)到根节点的距离 dis[rt] int
4)到父亲节点的距离 fadis[rt] int
5)父亲 father[rt] int
2. LCA的预处理,处理出F[rt][i],表示节点rt的第2i个祖先(即节点rt的祖先中与之深度相差rt的祖先) // F[rt][i] 在代码中写成 Anst[rt][i]
转移表达式为:F[rt][i]=F[F[rt][i-1]][i-1] 应该都能够理解
3. 求取LCA: 这里用的倍增的方法,虽然比离线算法LCA_Tarjan慢一个log,但是倍增是一个好东西,不妨去练练。这样思考:对于两个深度为d的节点a和b,使得int i=log2(d),那么就可以倍增:对于节点a和b,如果他们的第2i个祖先是相同的,那么他们在网上的祖先也一定是相同的 ,那么我们就对于不改变a和b的值,而使i=i-1;如果他们的第2i个祖先不同,那么他们往下走的祖先也是不同的,于是就可以确定他们的最近公共祖先一定是在第2i个祖先上面的,那么我们就可以安心的把a和b的值更新乘F[a][i]和F[b][i](a=F[a][i],b=F[b][i])。直到i为0位置,无法再做了。于是,a和b的最近公共祖先就是a和b的父亲,即F[a][0]或F[b][0](相等的)。于是剩下的只是把a和b调到同一深度这点事情了。设b为深度更大的那个,设deep[x]为x的深度,那么把b移上去,就是求b个第(deep[b]-deep[a])个祖先,也是倍增可以解决的。
至于LCA_Tarjan,可以自己学啊!这里就不多说了。
3.二分答案:不用说了吧,就是一个基本的二分
4.check(答案):这个在大佬的题解里面写的比较详细,可以看他的~
1 #pragma comment(linker, "/STACK:10240000,10240000")
2 #include <cstring>
3 #include <algorithm>
4 #include <cstdio>
5 #include <cstdlib>
6 #include <cmath>
7 #include <vector>
8 using namespace std;
9 const int N=300000+5,M=N*2,Inf=N*1000;
10 void read(int &x){
11 x=0;
12 char ch=getchar();
13 while (!('0'<=ch&&ch<='9'))
14 ch=getchar();
15 while ('0'<=ch&&ch<='9'){
16 x=x*10+ch-48;
17 ch=getchar();
18 }
19 }
20 struct Edge{
21 int cnt,y[M],z[M],nxt[M],fst[N];
22 void set(){
23 cnt=0;
24 memset(y,0,sizeof y);
25 memset(z,0,sizeof z);
26 memset(nxt,0,sizeof nxt);
27 memset(fst,0,sizeof fst);
28 }
29 void add(int a,int b,int c){
30 cnt++;
31 y[cnt]=b,z[cnt]=c;
32 nxt[cnt]=fst[a],fst[a]=cnt;
33 }
34 }e;
35 int n,m;
36 vector <int> Tree[N];
37 int father[N],son[N],deep[N],dis[N],fadis[N],bh[N],bhtot;
38 int Anst[N][20];//Ancestor
39 struct Query{
40 int x,y,LCA,cost;
41 }q[N];
42 int Nextsum[N];
43 void Build_Tree(int prev,int rt){
44 bh[++bhtot]=rt;
45 Tree[rt].clear();
46 deep[rt]=deep[prev]+1;
47 son[rt]=0;
48 father[rt]=prev;
49 for (int i=e.fst[rt];i;i=e.nxt[i])
50 if (e.y[i]!=prev){
51 son[rt]++,Tree[rt].push_back(e.y[i]);
52 fadis[e.y[i]]=e.z[i];
53 dis[e.y[i]]=dis[rt]+e.z[i];
54 Build_Tree(rt,e.y[i]);
55 }
56 }
57 void LCA_Prepare(){
58 memset(Anst,0,sizeof Anst);
59 for (int i=1;i<=n;i++){
60 int rt=bh[i];
61 Anst[rt][0]=father[rt];
62 for (int i=1;(1<<i)<=deep[rt];i++)
63 Anst[rt][i]=Anst[Anst[rt][i-1]][i-1];
64 }
65 }
66 int LCA(int a,int b){
67 if (deep[a]>deep[b])
68 swap(a,b);
69 for (int i=deep[b]-deep[a],j=0;i>0;i>>=1,j++)
70 if (i&1)
71 b=Anst[b][j];
72 if (a==b)
73 return a;
74 int k;
75 for (k=0;(1<<k)<=deep[a];k++);
76 for (;k>=0;k--)
77 if ((1<<k)<=deep[a]&&Anst[a][k]!=Anst[b][k])
78 a=Anst[a][k],b=Anst[b][k];
79 return Anst[a][0];
80 }
81 bool check(int t){
82 int total=0,Maxcost=0,Maxcut=0;
83 memset(Nextsum,0,sizeof Nextsum);
84 for (int i=1;i<=m;i++)
85 if (q[i].cost>t){
86 Maxcost=max(Maxcost,q[i].cost-t);
87 total++;
88 Nextsum[q[i].x]++;
89 Nextsum[q[i].y]++;
90 Nextsum[q[i].LCA]-=2;
91 }
92 for (int i=n;i>=1;i--)
93 Nextsum[father[bh[i]]]+=Nextsum[bh[i]];
94 for (int i=1;i<=n;i++)
95 if (Nextsum[i]==total)
96 Maxcut=max(Maxcut,fadis[i]);
97 return Maxcost<=Maxcut;
98 }
99 int main(){
100 scanf("%d%d",&n,&m);
101 e.set();
102 for (int i=1;i<n;i++){
103 int a,b,c;
104 read(a),read(b),read(c);
105 e.add(a,b,c);
106 e.add(b,a,c);
107 }
108 bhtot=0;
109 deep[0]=-1,dis[1]=fadis[1]=0;
110 Build_Tree(0,1);
111 LCA_Prepare();
112 for (int i=1;i<=m;i++){
113 read(q[i].x),read(q[i].y);
114 q[i].LCA=LCA(q[i].x,q[i].y);
115 q[i].cost=dis[q[i].x]+dis[q[i].y]-dis[q[i].LCA]*2;
116 }
117 int le=0,ri=Inf,mid,ans=0;
118 while (le<=ri){
119 mid=(le+ri)>>1;
120 if (check(mid))
121 ri=mid-1,ans=mid;
122 else
123 le=mid+1;
124 }
125 printf("%d",ans);
126 return 0;
127 }