hdu4912 Paths on the tree --- LCA贪心

给一棵n个结点的树,m条路径的起点和终点,

问至多可以选择多少条路径使其两两间没有公共点。

这题的主要问题是,

1、如何判断两条路径上没有交点

2、按什么策略来选

看上去感觉是最大匹配问题,但nm的范围较大问题1无法高效的解决。

画个图发现可能和LCA有关,但比赛时不知道这到底有什么用,完全没想贪心。

要选择尽量多,就是要尽量避免冲突。

我们选择一个点作为根,把给的边画出来建树就可以发现,尽量选深度大的路径可以使冲突尽量小。

于是把路径按LCA深度由大到小排序,依次和之前不冲突就可以选。

下面就是判断两条路径上有没有交点,

当一条路径选了之后,以其LCA的子树上的点为起点或终点的路径一定与其有交点。

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#define inf 0x3f3f3f3f
#pragma comment(linker, "/STACK:16777216")
#define eps 1e-6
#define ll long long
using namespace std;

const int maxn=1e5+10;
int dep[maxn];
struct node
{
    int v,id;
    node* next;
}ed[maxn<<2],*head[maxn],*q[maxn];

struct qnode
{
    int u,v,ans;//存询问结点,ans最近公共祖先
} qu[maxn];

bool cmp(const qnode &a,const qnode &b)
{
    return dep[a.ans]>dep[b.ans];
}

int fa[maxn],vis[maxn],cnt;

void init(int n)
{
    cnt=0;
    memset(vis,0,sizeof vis);
    memset(head,0,sizeof head);
    memset(q,0,sizeof q);
    for(int i=0;i<=n;i++)
        fa[i]=i;
}

int getfa(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=getfa(fa[x]);
}

void tarjan(int u)
{
    fa[u]=u,vis[u]=1;
    for(node *p=q[u];p!=NULL;p=p->next)
    {
        if(vis[p->v])
        {
            int id=p->id;
            qu[id].ans=getfa(p->v);
        }
    }
    for(node *p=head[u];p!=NULL;p=p->next)
    {
        if(!vis[p->v])
        {
            tarjan(p->v);
            fa[p->v]=u;
        }
    }
}

void adde(node *e[],int u,int v,int id)
{
    ed[cnt].v=v;
    ed[cnt].id=id;
    ed[cnt].next=e[u];
    e[u]=&ed[cnt++];
}

void dfs(int u)
{
    for(node *p=head[u];p!=NULL;p=p->next)
    {
        if(dep[p->v]>dep[u]&&!vis[p->v])
        {
            vis[p->v]=1;
            dfs(p->v);
        }
    }
}

void dfss(int u,int d)
{
    for(node *p=head[u];p!=NULL;p=p->next)
    {
        if(!vis[p->v])
        {
            vis[p->v]=1;
            dep[p->v]=d;
            dfss(p->v,d+1);
        }
    }
}

int main()
{
    int n,m,i,a,b;
    while(~scanf("%d%d",&n,&m))
    {
        init(n);
        for(i=0;i<n-1;i++)
        {
            scanf("%d%d",&a,&b);
            adde(head,a,b,i);
            adde(head,b,a,i);
        }
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&a,&b);
            qu[i].u=a;
            qu[i].v=b;
            adde(q,a,b,i);
            adde(q,b,a,i);
        }

        memset(vis,0,sizeof vis);
        dep[1]=0;vis[1]=1;
        dfss(1,1);//预处理 标号-深度

        memset(vis,0,sizeof vis);
        tarjan(1);//以1为根找lca

        int ans=0;
        sort(qu,qu+m,cmp);
        memset(vis,0,sizeof vis);
        for(i=0;i<m;i++)
        {
            //printf("s:%d t:%d p:%d dep:%d\n",qu[i].u,qu[i].v,qu[i].ans,dep[qu[i].ans]);
            if(!vis[qu[i].u]&&!vis[qu[i].v]&&!vis[qu[i].ans])
            {
                ans++;
                vis[qu[i].ans]=1;
                dfs(qu[i].ans);//标记子树
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

hdu4912 Paths on the tree --- LCA贪心,布布扣,bubuko.com

时间: 2024-10-10 17:29:17

hdu4912 Paths on the tree --- LCA贪心的相关文章

HDU 4912 Paths on the tree LCA 排序贪心

lca... 排个序然后暴力保平安 _(:зゝ∠)_ #pragma comment(linker, "/STACK:102400000,102400000") #include"cstdio" #include"iostream" #include"set" #include"queue" #include"string.h" using namespace std; #define

hdu 4912 Paths on the tree(lca+馋)

意甲冠军:它使树m路径,当被问及选择尽可能多的路径,而这些路径不相交. 思考:贪心,比較忧伤.首先求一下每对路径的lca.依照lca的层数排序.在深一层的优先级高.那么就能够贪心了,每次选择层数最深的那一个,假设两个端点没有被标记,那么就选择这条路径,把lca的子树都标记掉. 代码: #pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<cstdio>

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

题目链接 Paths on the tree 来源  2014 多校联合训练第5场 Problem B 题意就是给出m条树上的路径,让你求出可以同时选择的互不相交的路径最大数目. 我们先求出每一条路径(u, v)中u和v的LCA:w,按照路径的w的深度大小deep[w]对所有的路径排序. deep[w]越大,排在越前面. 然后从第一条路径开始一次处理,看c[u]和c[v]是否都没被标记过,如果都没被标记过则我们把这条路径选上,把答案加1. 同时标记以w为根的子树的节点为1,方便后续对c数组的查询

hdu 4912 Paths on the tree(树链剖分+贪心)

题目链接:hdu 4912 Paths on the tree 题目大意:给定一棵树,和若干个通道,要求尽量选出多的通道,并且两两通道不想交. 解题思路:用树链剖分求LCA,然后根据通道两端节点的LCA深度排序,从深度最大优先选,判断两个节点均没被标 记即为可选通道.每次选完通道,将该通道LCA以下点全部标记. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include

【HDU4912】Paths on the tree

题面 bobo有一棵树,其顶点方便地用1,2...n标记. 树上有m条路径. BOBO想挑一些路径,同时任何两个路径不共享共同的顶点. 找到bobo可以选择的最大路径数. 输入包括几个测试. 对于每个测试: 第一行包含n,m(1≤n,m≤105). 以下(n-1)行中的每一行包含2个整数a i,b i表示顶点a i和b i之间的边(1≤ai,bi≤n). 之后m行中的每一行包含2个整数u i,v i表示顶点u i和v i之间的路径(1≤ui,vi≤n). 对于每组数据,输出一个最大路径数. 分析

HDU 4912 LCA+贪心

Paths on the tree Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 531    Accepted Submission(s): 182 Problem Description bobo has a tree, whose vertices are conveniently labeled by 1,2,…,n. Th

HDU 4912 Paths on the tree

http://acm.hdu.edu.cn/showproblem.php?pid=4912 题意:给一棵树,再给一些路径,求最多有多少条路径不相交. 题解:主要是贪心的想法.用LCA处理出路径的层数,然后从最深处的节点往上找.因为节点越深,对其他路径影响度越小,相交的可能性越低.需要手动扩栈. 1 #pragma comment(linker, "/STACK:1024000000,1024000000") 2 #include <iostream> 3 #include

HDU 4912 lca贪心

Paths on the tree Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 297    Accepted Submission(s): 93 Problem Description bobo has a tree, whose vertices are conveniently labeled by 1,2,-,n. Th

hdu 4912 Paths on the tree(树链拆分+贪婪)

题目链接:hdu 4912 Paths on the tree 题目大意:给定一棵树,和若干个通道.要求尽量选出多的通道,而且两两通道不想交. 解题思路:用树链剖分求LCA,然后依据通道两端节点的LCA深度排序,从深度最大优先选.推断两个节点均没被标 记即为可选通道. 每次选完通道.将该通道LCA下面点所有标记. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #includ