BZOJ 1509 [NOI2003]逃学的小孩

题意:给定一棵树,设A, B, C为树上的三个不相同的点,求出max{dist(A, B) + min{dist(C, A), dist(C, B)}}

首先,如果dist(A,B)最大的话,很显然这是树上的一条最长链。也就是说,A和B是树上任意一条最长链的两个端点。

然后,我们有一个结论:树上某个点的最远点必定是树上任意一条最长链的两个端点中的一个。。

综合上面两个结论我们可以得到,当dist(A, B)和min{dist(C, A), dist(C, B)}同时取最大时,都与树上的最长链有关。。

毫不犹豫的求出最长链,并记录下它的两个端点A和B。然后枚举点C就可以啦~

求最长链的时间复杂度是O(N),求出A和B到每个点的距离的时间复杂度是O(N),枚举C的时间复杂度是O(N)。。因此总的时间复杂度就是O(N)

  1 #include <queue>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <iostream>
  5
  6 using namespace std;
  7
  8 const size_t Max_N(200050);
  9 const size_t Max_M(400050);
 10
 11 size_t N;
 12
 13 unsigned int Total;
 14 unsigned int Head[Max_N];
 15 unsigned int To[Max_M];
 16 unsigned long long int Weight[Max_M];
 17 unsigned int Next[Max_M];
 18
 19 inline
 20 unsigned long long int Max(const unsigned long long int &a, const unsigned long long int &b)
 21 {
 22     return a > b ? a : b;
 23 }
 24
 25 inline
 26 unsigned long long int Min(const unsigned long long int &a, const unsigned long long int &b)
 27 {
 28     return a < b ? a : b;
 29 }
 30
 31 inline
 32 void Add_Edge(const size_t &s, const size_t &t, const unsigned long long int &w)
 33 {
 34     ++Total, To[Total] = t, Weight[Total] = w, Next[Total] = Head[s], Head[s] = Total;
 35 }
 36
 37 void init()
 38 {
 39     unsigned int M;
 40     size_t u, v;
 41     unsigned long long int w;
 42
 43     cin >> N >> M;
 44     while (M--)
 45     {
 46         cin >> u >> v >> w;
 47         Add_Edge(u, v, w);
 48         Add_Edge(v, u, w);
 49     }
 50 }
 51
 52 struct node
 53 {
 54     node(const unsigned int &a = 0, const unsigned long long int &b = 0) : now(a), wsum(b) {}
 55     unsigned int now;
 56     unsigned long long int wsum;
 57 };
 58
 59 size_t A, B;//树上最长链的两个端点
 60
 61 unsigned long long int Dist_A[Max_N], Dist_B[Max_N];
 62 //分别存储A到各个点的距离和B到各个点的距离
 63
 64 unsigned long long int Now_Max;
 65 bool In_Q[Max_N];
 66
 67 void BFS_1()
 68 {
 69     Now_Max = 0ULL;
 70     queue<node> Q;
 71     Q.push(node(1, 0ULL));
 72     In_Q[1] = true;
 73     node Top;
 74     while (Q.size())
 75     {
 76         Top = Q.front();
 77         Q.pop();
 78         if (Top.wsum > Now_Max)
 79         {
 80             Now_Max = Top.wsum;
 81             A = Top.now;
 82         }
 83         for (size_t i = Head[Top.now];i;i = Next[i])
 84             if (!In_Q[To[i]])
 85             {
 86                 In_Q[To[i]] = true;
 87                 Q.push(node(To[i], Top.wsum + Weight[i]));
 88             }
 89     }
 90 }
 91
 92 void BFS_2()
 93 {
 94     Now_Max = 0ULL;
 95     memset(In_Q, false, sizeof(In_Q));
 96     queue<node> Q;
 97     Q.push(node(A, 0ULL));
 98     In_Q[A] = true;
 99     node Top;
100     while (Q.size())
101     {
102         Top = Q.front();
103         Q.pop();
104         if (Top.wsum > Now_Max)
105         {
106             Now_Max = Top.wsum;
107             B = Top.now;
108         }
109         for (size_t i = Head[Top.now];i;i = Next[i])
110             if (!In_Q[To[i]])
111             {
112                 In_Q[To[i]] = true;
113                 Q.push(node(To[i], Top.wsum + Weight[i]));
114             }
115     }
116 }
117
118 void BFS_A()//求出A到各个点的距离
119 {
120     memset(In_Q, false, sizeof(In_Q));
121     queue<unsigned int> Q;
122     Q.push(A);
123     In_Q[A] = true;
124     unsigned int Top;
125     while (Q.size())
126     {
127         Top = Q.front();
128         Q.pop();
129         for (size_t i = Head[Top];i;i = Next[i])
130             if (!In_Q[To[i]])
131             {
132                 In_Q[To[i]] = true;
133                 Q.push(To[i]);
134                 Dist_A[To[i]] = Dist_A[Top] + Weight[i];
135             }
136     }
137 }
138
139 void BFS_B()//求出B到各个点的距离
140 {
141     memset(In_Q, false, sizeof(In_Q));
142     queue<unsigned int> Q;
143     Q.push(B);
144     In_Q[B] = true;
145     unsigned int Top;
146     while (Q.size())
147     {
148         Top = Q.front();
149         Q.pop();
150         for (size_t i = Head[Top];i;i = Next[i])
151             if (!In_Q[To[i]])
152             {
153                 In_Q[To[i]] = true;
154                 Q.push(To[i]);
155                 Dist_B[To[i]] = Dist_B[Top] + Weight[i];
156             }
157     }
158 }
159
160 void Longest_Path()//求出最长链相关信息
161 {
162     BFS_1();
163     BFS_2();
164     BFS_A();
165     BFS_B();
166 }
167
168 void Get_Ans()
169 {
170     unsigned long long int Ans(0ULL);
171     for (size_t i = 1;i <= N;++i)
172         Ans = Max(Ans, Now_Max + Min(Dist_A[i], Dist_B[i]));
173     cout << Ans << endl;
174 }
175
176 int main()
177 {
178     init();
179
180     Longest_Path();
181
182     Get_Ans();
183
184     return 0;
185 }

BZOJ 1509

时间: 2024-10-16 04:04:03

BZOJ 1509 [NOI2003]逃学的小孩的相关文章

BZOJ 1509: [NOI2003]逃学的小孩( 树形dp )

树形dp求出某个点的最长3条链a,b,c(a>=b>=c), 然后以这个点为交点的最优解一定是a+2b+c.好像还有一种做法是求出树的直径然后乱搞... --------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<cctype> using

1509: [NOI2003]逃学的小孩 - BZOJ

Description Input 第一行是两个整数N(3 ? N ? 200000)和M,分别表示居住点总数和街道总数.以下M行,每行给出一条街道的信息.第i+1行包含整数Ui.Vi.Ti(1?Ui, Vi ? N,1 ? Ti ? 1000000000),表示街道i连接居住点Ui和Vi,并且经过街道i需花费Ti分钟.街道信息不会重复给出.Output 仅包含整数T,即最坏情况下Chris的父母需要花费T分钟才能找到Chris.Sample Input 4 3 1 2 1 2 3 1 3 4

NOI2003 逃学的小孩

这一题不会做啊-- 我觉得真要比赛的话我可能会随机上几万次,然后再用LCA求距离,更新最优值,等到快超时的时候输出答案-- 题解请看2007年陈瑜希论文 代码: 1 const maxn=400100; 2 type node=record 3 w,go,next:longint; 4 end; 5 var e:array[0..maxn] of node; 6 f:array[0..maxn,1..3] of int64; 7 first,u:array[0..maxn] of longint

BZOJ1509 NOI2003 逃学的小孩

Description: Input: 第一行是两个整数N(3 ? N ? 200000)和M,分别表示居住点总数和街道总数.以下M行,每行给出一条街道的信息.第i+1行包含整数Ui.Vi.Ti(1?Ui, Vi ? N,1 ? Ti ? 1000000000),表示街道i连接居住点Ui和Vi,并且经过街道i需花费Ti分钟.街道信息不会重复给出. Output: 仅包含整数T,即最坏情况下Chris的父母需要花费T分钟才能找到Chris. 思路:由于规则2,可知题目给出的是一棵树 然后求一根直径

(树直径) bzoj 1509

1509: [NOI2003]逃学的小孩 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 447  Solved: 240[Submit][Status][Discuss] Description Input 第一行是两个整数N(3 ? N ? 200000)和M,分别表示居住点总数和街道总数.以下M行,每行给出一条街道的信息.第i+1行包含整数Ui.Vi.Ti(1?Ui, Vi ? N,1 ? Ti ? 1000000000),表示街道i连接居住点U

【BZOJ1509】逃学的小孩

1509: [NOI2003]逃学的小孩 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 822  Solved: 409[Submit][Status][Discuss] Description Input 第一行是两个整数N(3 ? N ? 200000)和M,分别表示居住点总数和街道总数.以下M行,每行给出一条街道的信息.第i+1行包含整数Ui.Vi.Ti(1?Ui, Vi ? N,1 ? Ti ? 1000000000),表示街道i连接居住点U

BZOJ 1507 NOI2003 Editor Splay

题目大意: 1.将光标移动到某一位置 2.在光标后插入一段字符串 3.删除光标后的一段字符 4.输出光标后的一段字符 5.光标-- 6.光标++ 和1269很像的一道题,不过弱多了 几个问题需要注意: 1.插入的字符串中间居然会有回车!!没办法了,只能逐个字符进行读入,一旦读到'\n'或者'\r'就重新读入 2.题目描述中说Delete和Get操作后面一定会有足够的字符 纯属放P 连样例都没有足够的字符用来删除 所以删除时要和字符串长度取一个最小值 然后就水水地过去了~ 30%达成 今天是不是可

bzoj 1507: [NOI2003]Editor

1 #include<cstdio> 2 #include<iostream> 3 #include<ext/rope> 4 using namespace std; 5 using namespace __gnu_cxx; 6 crope list; 7 int n,now; 8 char ch[10],ch1[3000005]; 9 int main() 10 { 11 scanf("%d",&n); 12 for(int i=1;i&l

【树的直径应用】 逃学的小孩

题目 Chris家的电话铃响起了,里面传出了Chris的老师焦急的声音:“喂,是Chris的家长吗?你们的孩子又没来上课,不想参加考试了吗?”一听说要考试,Chris的父母就心急如焚,他们决定在尽量短的时间内找到Chris.他们告诉Chris的老师:“根据以往的经验,Chris现在必然躲在朋友Shermie或Yashiro家里偷玩<拳皇>游戏.现在,我们就从家出发去找Chris,一但找到,我们立刻给您打电话.”说完砰的一声把电话挂了. Chris居住的城市由N个居住点和若干条连接居住点的双向街