您的位置:首页 > 理论基础 > 计算机网络

HDU 6203 2017沈阳网络赛 LCA,DFS+树状数组

2017-09-13 16:51 471 查看

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6203

题意:n+1 个点 n 条边的树(点标号 0 ~ n),有若干个点无法通行,导致 p 组

U V
无法连通。问无法通行的点最少有多少个。

解法:按照询问的LCA深度排序,然后顺序标记每个询问的LCA。根据所给的树(任意点为根)预处理出每个点的前序 DFS 序和后序 DFS 序(需统一标号),及点的深度。根据 p 组

U V
处理每组两点的 LCA 。压入优先队列(LCA 深度大的点优先出队)。对于出队的
U V
及其对应的 LCA ,判断点 U 或点 V 是否在之前已禁止的某点的子树中,对于某点U如果在禁止通行的点P的子树中,则L[P]<=L[U]<=R[U]<=R[P]一定成立。所以可以利用树状数组区间更新单点查询,对于每个禁止通行点标记区间L[P],R[P]的所有节点。查询的时候如果L[U]被标记,说明U,V已经被隔断。

 

#include <bits/stdc++.h>
using namespace std;
const int maxn = 20100;
typedef long long LL;
vector <int> G[maxn];
int n, m, dfsclk, c[maxn], fa[maxn][21], dep[maxn], L[maxn], R[maxn];
bool vis[maxn];
struct node{
int u,v,uv;
node(){}
node(int u,int v,int uv):u(u),v(v),uv(uv){}
bool operator<(const node &rhs)const{
return dep[uv]<dep[rhs.uv];
}
};
void dfs(int x){
vis[x]=1;
L[x]=++dfsclk;
for(int i=0; i<G[x].size(); i++){
int v=G[x][i];
if(!vis[v]){
dep[v]=dep[x]+1;
fa[v][0]=x;
dfs(v);
}
}
R[x]=++dfsclk;
}
void init(){
for(int j=1; j<=20; j++)
for(int i=1; i<=n; i++)
fa[i][j] = fa[fa[i][j-1]][j-1];
}
int LCA(int u, int v){
if(dep[u]<dep[v]) swap(u,v);
for(int i=20; i>=0; i--){
if((dep[u]-dep[v])&(1<<i))
u=fa[u][i];
}
if(u==v) return u;
for(int i=20; i>=0; i--){
if(fa[u][i]!=fa[v][i]){
u=fa[u][i];
v=fa[v][i];
}
}
return fa[u][0];
}
int lowbit(int x){
return x&(-x);
}
void add(int x, int v){
while(x<maxn){
c[x]+=v;
x+=lowbit(x);
}
}
void update(int x, int y, int z){
add(x, z);
add(y+1, -z);
}
int query(int x){
int ret=0;
while(x>0){
ret+=c[x];
x-=lowbit(x);
}
return ret;
}
int main()
{
while(~scanf("%d", &n))
{
memset(c, 0, sizeof(c));
memset(vis, 0, sizeof(vis));
memset(dep, 0, sizeof(dep));
for(int i=0; i<=n+1; i++) G[i].clear();
for(int i=1; i<=n; i++){
int u,v;
scanf("%d %d", &u,&v);
u++,v++;
G[u].push_back(v);
G[v].push_back(u);
}
n++;
dfsclk = 0;
dfs(1);
init();
priority_queue <node> q;
scanf("%d", &m);
while(m--){
int u, v;
scanf("%d %d", &u,&v);
u++;
v++;
int uv = LCA(u, v);
q.push(node(u,v,uv));
}
int ans=0;
while(!q.empty()){
node now = q.top();
q.pop();
int flag = query(L[now.u])+query(L[now.v]);
if(flag==0){
ans++;
update(L[now.uv],R[now.uv],1);
}
}
printf("%d\n", ans);
}
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: