hdu4912 贪心+lca

题意:给出一些树边组成一棵树,再给出一些路径,然后问在选择得点不能重叠得情况下 最多能够选择多少路径


解法:贪心得思想是在对于所有路径上两点得lca深度排序 优先选择深度比较小的 然后标记该路径不能选择

则可以选择出最多的路径  具体实现的时候要用并查集维护一下 如果没有找到就连到父节点上 如果找到了就把lca除外


#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define maxn 111111
#define D 20
int n,m,a[maxn],b[maxn],depth[maxn],pa[D][maxn],f[maxn];
vector<int>e[maxn],qu[maxn];
int lca(int a,int b){
    if(depth[a]>depth[b])swap(a,b);
    for(int i=D-1;i>=0;i--){
        if((depth[b]-depth[a])>>i&1){
            b=pa[i][b];
        }
    }
    if(a==b)return a;
    for(int i=D-1;i>=0;--i){
        if(pa[i][a]!=pa[i][b]){
            a=pa[i][a];b=pa[i][b];
        }
    }
    return pa[0][a];
}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
int main()
{
    while(~scanf("%d%d",&n,&m)){
        fill(e,e+n,vector<int>());//清空边
        for(int i=0;i<n-1;++i){
            int a,b;scanf("%d%d",&a,&b);--a;--b;
            e[a].push_back(b);e[b].push_back(a);
        }
        //calculator depth && init pa[0][]
        vector<int>queue;
        {
            int* parent=pa[0];
            depth[0]=0;
            parent[0]=-1;
            queue.push_back(0);
            for(int head=0;head<(int)queue.size();++head){
                int u=queue[head];
                for(int i=0;i<(int)e[u].size();++i){
                    int v=e[u][i];
                    if(v!=parent[u]){
                        depth[v]=depth[u]+1;
                        parent[v]=u;
                        queue.push_back(v);
                    }
                }
            }
        }
        //step
        for(int i=1;i<D;++i)
            for(int j=0;j<n;++j){
                int &x=pa[i][j];
                x=pa[i-1][j];
                if(~x)x=pa[i-1][x];
            }
        
        fill(qu,qu+n,vector<int>());
        
        for(int i=0;i<m;++i){
            scanf("%d%d",a+i,b+i);
            --a[i];--b[i];
            qu[lca(a[i],b[i])].push_back(i);
        }
        for(int i=0;i<n;++i)f[i]=i;
        int ans=0;
        for(int x=n-1;x>=0;--x){
            int u=queue[x];
            bool found=false;
            for(int y=0;y<(int)qu[u].size()&&!found;++y){
                int i=qu[u][y];
                if(find(a[i])==u&&find(b[i])==u){
                    found=true;
                }
            }
            if(!found){
                f[u]=pa[0][u];
            }else{
                ans++;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值