[BZOJ1468][POJ1741]Tree

仍然是点分治,点分治是个蛋具体参见[BZOJ2599][IOI2011]Race

这题和那题不一样的是,要求边权和<=K的。一个比较科学的统计方法是,统计出点u为根的树中所有的合法方案,再扣掉两条链都在同一子树内的不合法方案。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::vector;

const int MAXN = 40001;
struct Edge
{
  int v, w;
  Edge *next;
} g[MAXN*2], *header[MAXN];
void AddEdge(const int x, const int y, const int w)
{
  static int LinkSize;
  Edge* const node = g+(LinkSize++);
  node->v = y;
  node->w = w;
  node->next = header[x];
  header[x] = node;
}
int n, K, ans, parent[MAXN];
bool mark[MAXN];
std::queue<int> Q;
int GetCore(const int root)
{
  static int son[MAXN];
  static std::stack<int> s;
  int nodes = 0;
  for (Q.push(root), parent[root] = -1; !Q.empty(); Q.pop())
  {
    const int u = Q.front();
    s.push(u);
    ++nodes;
    for (Edge *e = header[u]; e; e = e->next)
      if (!mark[e->v] && parent[u] != e->v)
      {
        parent[e->v] = u;
        Q.push(e->v);
      }
  }
  int core, min = 0x3F3F3F3F;
  for (; !s.empty(); s.pop())
  {
    const int u = s.top();
    int cnt = 0, max = 0;
    for (Edge *e = header[u]; e; e = e->next)
      if (!mark[e->v] && parent[u] != e->v)
      {
        cnt += son[e->v];
        max = std::max(max, son[e->v]);
      }
    max = std::max(max, nodes-(son[u] = cnt+1));
    if (max < min)
      min = max, core = u;
  }
  return core;
}
inline int calc(const vector<int>& v)
{
  int res = 0;
  for (int i = 0, j = static_cast<int>(v.size())-1; i < j; )
    if (v[i] + v[j] <= K) res += j-i, ++i;
    else --j;
  return res;
}
void Solve(const int core)
{
  static int dist[MAXN];
  int ans0 = 0, ans1 = 0;
  mark[core] = true;
  vector<int> v;
  for (Q.push(core), dist[core] = 0, v.push_back(0), parent[core] = -1; !Q.empty(); Q.pop())
  {
    const int u = Q.front();
    for (Edge *e = header[u]; e; e = e->next)
      if (!mark[e->v] && parent[u] != e->v)
      {
        parent[e->v] = u;
        v.push_back(dist[e->v] = dist[u] + e->w);
        Q.push(e->v);
      }
  }
  std::sort(v.begin(), v.end());
  ans0 = calc(v);
  for (Edge *edge = header[core]; edge; edge = edge->next)
  {
    const int st = edge->v;
    if (mark[st]) continue;
    v.clear();
    for (Q.push(st), v.push_back(dist[st]); !Q.empty(); Q.pop())
    {
      const int u = Q.front();
      for (Edge *e = header[u]; e; e = e->next)
        if (!mark[e->v] && parent[u] != e->v)
        {
          v.push_back(dist[e->v]);
          Q.push(e->v);
        }
    }
    std::sort(v.begin(), v.end());
    ans1 += calc(v);
  }
  ans += ans0-ans1;
}

int main()
{
  scanf("%d", &n);
  for (int i = 1, x, y, w; i < n; ++i)
  {
    scanf("%d%d%d", &x, &y, &w);
    AddEdge(x, y, w);
    AddEdge(y, x, w);
  }
  scanf("%d", &K);
  std::queue<int> Q;
  for (Q.push(1); !Q.empty(); Q.pop())
  {
    const int core = GetCore(Q.front());
    Solve(core);
    for (Edge *e = header[core]; e; e = e->next)
      if (!mark[e->v])
        Q.push(e->v);
  }
  printf("%d", ans);
}

Comments