HDU-6203 ping ping ping(LCA+贪心)

题意

n 台服务器构成一棵树,给定 p 对无法通信的服务器对,求最少有多少台服务器出现故障。
1 n 10000
1 p 50000

思路

贪心比较明显,先考虑一个贪心的顺序。先处理出每个服务器对的 L C A ,假设比某对服务器 L C A 更深的服务器都已经断过了,那我们肯定要尽量往高的断,而且也只有 L C A 从深到浅的断才能保证决策清晰。由此得出算法:先对 L C A 由深到浅排序,每次都把 L C A 弄断,并把以这个 L C A 为根的子树中节点标记。服务器对中的某个点已经被标记过了,那么这次操作可以跳过(因为标记它的 L C A 肯定比现在的深,就说明这个点在半路上就已经断掉了)。而标记可以使用 d f s 序,再用树状数组区间改单点查。但何必呢?一个点被标记说明它的子树一定全被标记了,那就直接用 d f s 标记,发现某个点已被标记直接返回即可。复杂度和 p 个操作的复杂度是相加的,比树状数组不增反减。

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#define lowbit(x) ((x)&-(x))
#define N 10003
typedef long long LL;
using namespace std;
int bin[N],ans;
template<const int maxn,const int maxm>struct Linked_list
{
    int head[maxn],to[maxm],nxt[maxm],tot;
    void clear(){memset(head,-1,sizeof(head));tot=0;}
    void add(int u,int v){to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
    #define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
struct data
{
    int a,b,lca,lcaLV;
    bool operator <(const data &_)const{return lcaLV>_.lcaLV;}
};
struct Tree
{
    int lv[N],fa[N][20],mark[N],n;
    data D[N*5];
    Linked_list<N,N<<1>G;
    void reset(int _){n=_;G.clear();memset(mark,0,sizeof(mark));memset(fa,-1,sizeof(fa));}
    void add(int u,int v){G.add(u,v);G.add(v,u);}
    void dfs(int u,int d)
    {
        lv[u]=d;
        EOR(i,G,u)
        {
            int v=G.to[i];
            if(v!=fa[u][0])
            {
                fa[v][0]=u;
                dfs(v,d+1);
            }
        }
    }
    void redfs(int u)
    {
        if(mark[u])return;
        mark[u]=1;
        EOR(i,G,u)
        {
            int v=G.to[i];
            if(v!=fa[u][0])redfs(v);
        }
    }
    void make_fa()
    {
        FOR(j,1,19)
            FOR(i,1,n)
                if(~fa[i][j-1])
                    fa[i][j]=fa[fa[i][j-1]][j-1];
    }
    void jmp(int &x,int stp)
    {
        while(stp)
        {
            x=fa[x][bin[lowbit(stp)]];
            stp^=lowbit(stp);
        }
    }
    int LCA(int a,int b)
    {
        if(lv[a]>lv[b])jmp(a,lv[a]-lv[b]);
        else if(lv[b]>lv[a])jmp(b,lv[b]-lv[a]);
        if(a==b)return a;
        DOR(i,19,0)
            if(fa[a][i]!=fa[b][i])
            {
                a=fa[a][i];
                b=fa[b][i];
            }
        return fa[a][0];
    }
    void Read_data(int Q)
    {
        FOR(i,1,Q)
        {
            scanf("%d%d",&D[i].a,&D[i].b);
            D[i].a++,D[i].b++;
            D[i].lcaLV=lv[D[i].lca=LCA(D[i].a,D[i].b)];
        }
        sort(D+1,D+1+Q);
    }
    void destro(int k)
    {
        if(mark[D[k].a]||mark[D[k].b])return;
        redfs(D[k].lca);
        ans++;
    }
}T;

int main()
{
    FOR(i,2,N-3)bin[i]=bin[i>>1]+1;
    int n,m;
    while(~scanf("%d",&n))
    {
        n++;
        ans=0;
        T.reset(n);
        FOR(i,1,n-1)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            T.add(u+1,v+1);
        }
        T.dfs(1,0);
        T.make_fa();
        scanf("%d",&m);
        T.Read_data(m);
        FOR(i,1,m)T.destro(i);
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Paulliant/article/details/81268800