Mart Master II
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 836 Accepted Submission(s): 306
Problem Description
Trader Dogy lives in city S, which consists of n districts. There are n - 1 bidirectional roads in city S, each connects a pair of districts. Indeed, city S is connected, i.e. people can travel between every pair of districts by roads.
In some districts there are marts founded by Dogy’s competitors. when people go to marts, they’ll choose the nearest one. In cases there are more than one nearest marts, they’ll choose the one with minimal city number.
Dogy’s money could support him to build only one new marts, he wants to attract as many people as possible, that is, to build his marts in some way that maximize the number of people who will choose his mart as favorite. Could you help him?
In some districts there are marts founded by Dogy’s competitors. when people go to marts, they’ll choose the nearest one. In cases there are more than one nearest marts, they’ll choose the one with minimal city number.
Dogy’s money could support him to build only one new marts, he wants to attract as many people as possible, that is, to build his marts in some way that maximize the number of people who will choose his mart as favorite. Could you help him?
Input
There are multiple test cases. Please process till EOF.
In each test case:
First line: an integer n indicating the number of districts.
Next n - 1 lines: each contains three numbers b i, e i and w i, (1 ≤ b i,e i ≤ n,1 ≤ w i ≤ 10000), indicates that there’s one road connecting city b i and e i, and its length is w i.
Last line : n(1 ≤ n ≤ 10 5) numbers, each number is either 0 or 1, i-th number is 1 indicates that the i-th district has mart in the beginning and vice versa.
In each test case:
First line: an integer n indicating the number of districts.
Next n - 1 lines: each contains three numbers b i, e i and w i, (1 ≤ b i,e i ≤ n,1 ≤ w i ≤ 10000), indicates that there’s one road connecting city b i and e i, and its length is w i.
Last line : n(1 ≤ n ≤ 10 5) numbers, each number is either 0 or 1, i-th number is 1 indicates that the i-th district has mart in the beginning and vice versa.
Output
For each test case, output one number, denotes the number of people you can attract, taking district as a unit.
Sample Input
5 1 2 1 2 3 1 3 4 1 4 5 1 1 0 0 0 1 5 1 2 1 2 3 1 3 4 1 4 5 1 1 0 0 0 0 1 1 1 0
Sample Output
2 4 0 1
Source
Recommend
hujie
题意:给定一个n个点的图,这个图是一棵树,然后有些点建立了集市。并且没有集市的地方去集市一定是去最近的,如果距离相同,那么则去标号小的。现在再建一个集市,问建完这个集市最多有多少个点来这里
解题思路:树分治,先求出初始状态离每个点最近的关键点是哪个,然后再考虑用点分治求每个点作为关键点能覆盖的点的数量,当以root为根时如果u能覆盖v,那么应该有d[u] + d[v] < dis[v],其中dis[v]是事前预处理出来离v最近的关键点距离,也就是dis[u] < now[v] - dis[v],所以我们就可以把以root为根的这棵子树的所有点的dis都一遍dfs出来,然后枚举u来更新答案,注意这时在同一棵子树下的u和v会在点分治的过程中被多次重复计算,所以之后还要再减掉
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cctype>
#include <map>
#include <cmath>
#include <set>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <functional>
using namespace std;
#define LL long long
const int INF = 0x3f3f3f3f;
const int maxn = 2e5 + 10;
int n, m, x, y, w;
int s[maxn], nt[maxn], e[maxn], val[maxn], cnt;
int sum[maxn], mx[maxn], dis[maxn], vis[maxn];
int id[maxn], flag[maxn], ans[maxn], tot;
struct node
{
int id, dis, flag;
node(int id = 0, int dis = 0, int flag = 0) :id(id), dis(dis), flag(flag) {}
bool operator<(const node &a)const
{
if (dis != a.dis) return dis > a.dis;
else return flag > a.flag;
}
}pre;
pair<int, int>d[maxn], D[maxn];
void Dijkstra()
{
priority_queue<node>q;
memset(vis, 0, sizeof vis);
memset(dis, INF, sizeof dis);
for (int i = 1; i <= n; i++)
{
scanf("%d", &flag[i]);
if (flag[i]) q.push(node(i, dis[i] = 0, id[i] = i));
}
while (!q.empty())
{
pre = q.top();
q.pop();
vis[pre.id] = 1;
for (int i = s[pre.id]; ~i; i = nt[i])
{
if (vis[e[i]]) continue;
if (dis[e[i]] > pre.dis + val[i])
{
dis[e[i]] = pre.dis + val[i];
id[e[i]] = pre.flag;
q.push(node(e[i], dis[e[i]], id[e[i]]));
}
else if (dis[e[i]] == pre.dis + val[i] && id[e[i]] > pre.flag)
{
id[e[i]] = pre.flag;
q.push(node(e[i], dis[e[i]], id[e[i]]));
}
}
}
memset(vis, 0, sizeof vis);
}
int dfs(int k, int fa, int p)
{
int ans = 0;
sum[k] = (mx[k] = 0) + 1;
for (int i = s[k]; ~i; i = nt[i])
{
if (e[i] == fa || vis[e[i]]) continue;
int temp = dfs(e[i], k, p);
sum[k] += sum[e[i]];
mx[k] = max(mx[k], sum[e[i]]);
if (mx[temp] < mx[ans]) ans = temp;
}
mx[k] = max(mx[k], p - sum[k]);
return mx[k] < mx[ans] ? k : ans;
}
void get(int k, int fa, int len)
{
d[tot++] = make_pair(k, len);
for (int i = s[k]; ~i; i = nt[i])
{
if (vis[e[i]] || fa == e[i]) continue;
get(e[i], k, len + val[i]);
}
}
void Find(int k, int p, int len)
{
tot = 0;
get(k, k, len);
for (int i = 0; i < tot; i++) D[i] = make_pair(dis[d[i].first] - d[i].second, id[d[i].first]);
sort(D, D + tot);
for (int i = 0; i < tot; i++)
{
int k = lower_bound(D, D + tot, make_pair(d[i].second, d[i].first)) - D;
ans[d[i].first] += p*(tot - k);
}
}
void build(int k, int p)
{
int y = dfs(k, k, p);
Find(y, 1, 0), vis[y] = 1;
for (int i = s[y]; ~i; i = nt[i])
{
if (vis[e[i]]) continue;
Find(e[i], -1, val[i]);
if (sum[e[i]] < sum[y]) build(e[i], sum[e[i]]);
else build(e[i], p - sum[y]);
}
}
int main()
{
while (~scanf("%d", &n))
{
memset(s, -1, sizeof s);
memset(ans, 0, sizeof ans);
mx[cnt = 0] = INF;
for (int i = 1; i < n; i++)
{
scanf("%d%d%d", &x, &y, &w);
nt[cnt] = s[x], s[x] = cnt, e[cnt] = y, val[cnt++] = w;
nt[cnt] = s[y], s[y] = cnt, e[cnt] = x, val[cnt++] = w;
}
Dijkstra();
build(1, n);
int res = 0;
for (int i = 1; i <= n; i++)
if (!flag[i]) res = max(ans[i], res);
printf("%d\n", res);
}
return 0;
}