HDU 4912 Paths on the tree (LCA+贪心)

题目大意:给出一棵树和一些点对,要求出最多可以同时有多少点对同时存在并且路径不重复覆盖。

用tanjan的LCA求出所有点对的最近公共祖先,再按照最近公共祖先在树上的深度排序,优先选择LCA深度深的点对,然后将LCA所在的子树标记,以后不能再选。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;
const int maxn=200000+10;//树的点的两倍;

struct edge
{
    int u,v,c,next;
}e[maxn];

struct Q
{
    int u,v,next;
    int lca,no;
}que[maxn];

int head[maxn],cnt;
int head_que[maxn],cnt_que;
int n,m;
int father[maxn];
bool vis[maxn];
//int dist[maxn];
int deep[maxn];
int fa[maxn];

int flag[maxn],num;
void add(int u,int v)
{
    e[cnt].u=u;
    e[cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
void add_que(int u,int v)
{
    que[cnt_que].u=u;
    que[cnt_que].v=v;
    que[cnt_que].next=head_que[u];
    head_que[u]=cnt_que++;
}
void readtree(int n)
{
    int u,v,c;
    for (int i=1;i<n;i++)
        {
           // scanf("%d%d%d",&u,&v,&c);
           scanf("%d%d",&u,&v);
            //add(u,v,c);
           // add(v,u,c);
           add(u,v);
            add(v,u);
        }
}
void readque(int m)
{
    int u,v;
    for (int i=0;i<m;i++)
    {
            scanf("%d%d",&u,&v);
            if (flag[u]<flag[v])
            {
                add_que(v,u);
            }
            else add_que(u,v);
            que[i].no=i;
    }
}
void init()
{
    memset(head,-1,sizeof(head));
    cnt=0;
    memset(head_que,-1,sizeof(head_que));
    cnt_que=0;
}
int find(int p)//并查集
{
    return p==father[p]?p:father[p]=find(father[p]);
}
void dfs(int p,int fa)
{
    father[p]=p;
    for (int i=head[p];i!=-1;i=e[i].next)
    if (e[i].v!=fa)
    {
        dfs(e[i].v,p);
        father[e[i].v]=p;
    }
    vis[p]=1;

    for (int i=head_que[p];i!=-1;i=que[i].next)
        if (vis[que[i].v])
        que[i].lca=find(que[i].v);
}
void LCA(int root)
{
    memset(vis,0,sizeof(vis));
    memset(father,0,sizeof(father));//并查集用
    dfs(root,root);
}
bool cmp(Q a ,Q b)
{
    return deep[a.lca]>deep[b.lca];
}
void dfs_flag(int p,int fa)
{
//cout<<"P="<<p<<endl;
    for (int i=head[p];i!=-1;i=e[i].next)
        if (e[i].v!=fa)
        {
            dfs_flag(e[i].v,p);
           // cout<<"P="<<p<<endl;
        }
        flag[p]=num++;
}
//void dfs_dist(int p,int fa)
//{
//    for (int i=head[p];i!=-1;i=e[i].next)
//        if (e[i].v!=fa)
//        {
//            dist[e[i].v]=dist[p]+e[i].c;
//            dfs_dist(e[i].v,p);
//        }
//}
void dfs_deep(int p)
{
    for (int i=head[p];i!=-1;i=e[i].next)
        if (e[i].v!=fa[p])
    {
        fa[e[i].v]=p;
        deep[e[i].v]=deep[p]+1;
        dfs_deep(e[i].v);
    }
}
void dfs_vis(int p)
{
    vis[p]=1;
    for (int i=head[p];i!=-1;i=e[i].next)
        if (e[i].v!=fa[p]&&!vis[e[i].v])
    {

        dfs_vis(e[i].v);
    }
}
int main()
{
    freopen("in.txt","r",stdin);
    int T;
    //scanf("%d",&T);
   // cout<<T<<endl;
    //while (T--)
    while (~scanf("%d%d",&n,&m))
    {
        //cout<<T<<endl;
        int root=1;
        init();
       // scanf("%d%d",&n,&m);
        readtree(n);//读入n个点的树;
       // cnt=0;
        num=0;
        dfs_flag(root,-1);//对树按照左右根标号;
        readque(m);//读入m个询问;
        LCA(1);//LCA

        deep[root]=1;
        fa[root]=root;
        dfs_deep(root);

        sort(que,que+m,cmp);
       // dist[root]=0;
       // dfs_dist(root,-1);
        int ans=0;
        memset(vis,0,sizeof(vis));
        for (int i=0;i<m;i++)
            if (!vis[que[i].u]&&!vis[que[i].v])
                {
                    dfs_vis(que[i].lca);
                    ans++;
                }
            cout<<ans<<endl;
//        for (int i=0;i<m;i++)
//            cout<<dist[que[i].u]+dist[que[i].v]-2*dist[que[i].lca]<<endl;
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值