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

题目链接: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;
}

 

posted @ 2017-09-13 16:51  zxycoder  阅读(170)  评论(0编辑  收藏  举报