传送门:HDU 6203
题意:给出n+1 个点的树,其中有若干个点无法通过,导致 p 组顶点对(u, v)之间无法连通。问无法通行的点最少有多少个。
思路:对p组(u,v)顶点对求LCA,并按LCA的深度排序,从深度最大的开始处理,然后在dfs序上进行标记,若当前顶点对之间已经不可达,则直接跳过,否则将其LCA在dfs序上标记出来。
具体标记及判断方法详见:点击打开链接
树状数组区间更新单点查询就很类似于imos和思想,也很常用。
代码:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 10050
#define MAXM 10050
#define inf 0x3f3f3f3f
typedef pair<int,int>P;
int dep[MAXN], pre_ord[MAXN], post_ord[MAXN];
int f[20][MAXN], pre[MAXN];
int cnt, tid;
struct node
{
int v, next;
node(int _v = 0, int _next = 0) : v(_v), next(_next) {}
}mp[MAXM * 2];
void init()
{
cnt = tid = 0;
memset(pre, -1, sizeof(pre));
}
void add(int u, int v)
{
mp[cnt] = node(v, pre[u]), pre[u] = cnt++;
mp[cnt] = node(u, pre[v]), pre[v] = cnt++;
}
void dfs(int u, int fa)
{
dep[u] = dep[fa] + 1;
pre_ord[u] = ++tid;
for(int i = pre[u]; ~i; i = mp[i].next)
{
int v = mp[i].v;
if(v == fa) continue;
dfs(v, u);
f[0][v] = u;
}
post_ord[u] = ++tid;
}
int lca_init(int n)
{
dep[1] = 1;
dfs(1, 0);
int k = 0,t = 1;
while(t <= n)t <<= 1,k++;
for(int i=0;i+1<k;i++)
{
for(int j=1;j<=n;j++)
{
f[i+1][j] = f[i][f[i][j]];
}
}
return k;
}
int lca(int u, int v, int MAX)
{
if(dep[u] < dep[v]) swap(u, v);
int k = dep[u] - dep[v];
for(int i = 0;i < MAX; i++)
{
if((k >> i) & 1)
u = f[i][u];
}
if(u == v)return u;
for(int i = MAX - 1;i >= 0; i--)
while(f[i][u] != f[i][v])
{
u = f[i][u];
v = f[i][v];
}
return f[0][u];
}
struct query{
int u, v, lca;
query(int _u = 0, int _v = 0, int _lca = 0) : u(_u), v(_v), lca(_lca) {}
bool operator < (query x) const
{
return dep[lca] > dep[x.lca];
}
}Q[MAXN * 5];
int bit[MAXN << 1];
void update(int i, int x)
{
while(i <= tid)
{
bit[i] += x;
i += i & -i;
}
}
int sum(int i)
{
int res = 0;
while(i)
{
res += bit[i];
i -= i & -i;
}
return res;
}
int main()
{
int T, n, u, v, q;
while(~scanf("%d", &n))
{
init();
memset(bit, 0, sizeof(bit));
for(int i = 1; i <= n; i++)
{
scanf("%d %d", &u, &v);
add(++u, ++v);
}
n++;
int up = lca_init(n);
scanf("%d", &q);
for(int i = 0; i < q; i++)
{
scanf("%d %d", &u, &v);
u++,v++;
Q[i] = query(u, v, lca(u, v, up));
}
sort(Q, Q + q);
int is, ans = 0;
for(int i = 0; i < q; i++)
{
is = sum(pre_ord[Q[i].u]) + sum(pre_ord[Q[i].v]);
if(!is)
{
ans++;
update(pre_ord[Q[i].lca], 1);
update(post_ord[Q[i].lca] + 1, -1);
}
}
cout << ans << endl;
}
return 0;
}