(贪心+倍增求LCA) hdu 4912

Paths on the tree

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1097    Accepted Submission(s): 366

Problem Description

bobo has a tree, whose vertices are conveniently labeled by 1,2,…,n.

There are m paths on the tree. bobo would like to pick some paths while any two paths do not share common vertices.

Find the maximum number of paths bobo can pick.

Input

The input consists of several tests. For each tests:

The first line contains n,m (1≤n,m≤105). Each of the following (n - 1) lines contain 2 integers ai,bi denoting an edge between vertices ai and bi (1≤ai,bi≤n). Each of the following m lines contain 2 integers ui,vi denoting a path between vertices ui and vi (1≤ui,vi≤n).

Output

For each tests:

A single integer, the maximum number of paths.

Sample Input

3 2
1 2
1 3
1 2
1 3
7 3
1 2
1 3
2 4
2 5
3 6
3 7
2 3
4 5
6 7

Sample Output

1
2

Author

Xiaoxu Guo (ftiasch)

Source

2014 Multi-University Training Contest 5

从最深的公共祖先开始选择,选完之后,他的所有子节点都不可能再选,不然就重复了

用倍增思想求解即可

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
using namespace std;
vector<int> e[100005];
struct node
{
    int x,y,z;
}mp[100005];
int n,m,vis[100005],deep[100005],f[100005][30],mark[100005];
void init()
{
    for(int i=1;i<=n;i++)
    {
        vis[i]=0;
        deep[i]=0;
        mark[i]=0;
        e[i].clear();
    }
    memset(f,0,sizeof(f));
}
void dfs(int u)
{
    vis[u]=1;
    for(int i=0;i<e[u].size();i++)
    {
        int v=e[u][i];
        if(v==f[u][0])
            continue;
        if(!vis[v])
        {
            deep[v]=deep[u]+1;
            f[v][0]=u;
            dfs(v);
        }
    }
}
void bz()
{
    for(int i=1;(1<<i)<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            f[j][i]=f[f[j][i-1]][i-1];
        }
    }
}
bool cmp(node a,node b)
{
    return deep[a.z]>deep[b.z];
}
int LCA(int x,int y)
{
    int i,j;
    if(deep[x]<deep[y])
        swap(x,y);
    for(i=0;(1<<i)<=deep[x];i++);
    i--;
    for(j=i;j>=0;j--)
    {
        if(deep[x]-(1<<j)>=deep[y])
        {
            x=f[x][j];
        }
    }
    if(x==y)
        return y;
    for(j=i;j>=0;j--)
    {
        if(f[x][j]!=f[y][j])
        {
            x=f[x][j];
            y=f[y][j];
        }
    }
    return f[x][0];
}
void col(int u)
{
    mark[u]=1;
    for(int i=0;i<e[u].size();i++)
    {
        int v=e[u][i];
        if(deep[v]==deep[u]+1&&!mark[v])
            col(v);
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            e[x].push_back(y);
            e[y].push_back(x);
        }
        f[1][0]=1;
        deep[1]=1;
        dfs(1);
        bz();
        for(int i=0;i<m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            mp[i].x=x,mp[i].y=y,mp[i].z=LCA(x,y);
        }
        int ans=0;
        sort(mp,mp+m,cmp);
        for(int i=0;i<m;i++)
        {
            if(!mark[mp[i].x]&&!mark[mp[i].y])
            {
                ans++;
                col(mp[i].z);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

  

时间: 2024-09-29 23:44:50

(贪心+倍增求LCA) hdu 4912的相关文章

HDU 4081 Qin Shi Huang&#39;s National Road System 最小生成树+倍增求LCA

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4081 Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5428    Accepted Submission(s): 1902 Problem Description

hdu 2586 How far away ? 倍增求LCA

倍增求LCA LCA函数返回(u,v)两点的最近公共祖先 #include <bits/stdc++.h> using namespace std; const int N = 40010*2; struct node { int v,val,next; node(){} node(int vv,int va,int nn):v(vv),val(va),next(nn){} }E[N]; int n,m; int tot,head[N],dis[N],f[N][20],dep[N]; void

【LCA】倍增求LCA

题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输出格式: 输出包含M行,每行包含一个正整数,依次为每一个询问的结果. 输入输出样例 输入样例#1: 复制 5 5 4 3 1 2 4

POJ 1986:Distance Queries(倍增求LCA)

http://poj.org/problem?id=1986 题意:给出一棵n个点m条边的树,还有q个询问,求树上两点的距离. 思路:这次学了一下倍增算法求LCA.模板. dp[i][j]代表第i个点的第2^j个祖先是哪个点,dp[i][0] = i的第一个祖先 = fa[i].转移方程:dp[i][j] = dp[dp[i][j-1][j-1]. 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm&g

tarjan,树剖,倍增求lca

1.tarjan求lca Tarjan(u)//marge和find为并查集合并函数和查找函数 { for each(u,v) //访问所有u子节点v { Tarjan(v); //继续往下遍历 marge(u,v); //合并v到u上 标记v被访问过; } for each(u,e) //访问所有和u有询问关系的e { 如果e被访问过; u,e的最近公共祖先为find(e); } } 2.倍增lca(在线) #include<bits/stdc++.h> using namespace st

【OI】倍增求LCA

╭(′▽`)╯ 总之,我们都知道lca是啥,不需要任何基础也能想出来怎么用最暴力的方法求LCA,也就是深度深的点先跳到深度浅的点的同一深度,然后一起向上一步步跳.这样显然太慢了! 所以我们要用倍增,倍增比较屌,直接2^k速度往上跳,而且复杂度和树剖lca差不多,那么步骤分为两步 1.让两个点到同一深度 2.到了同一深度同步往上跳 反正我一开始看的时候一直在想,万一跳过了怎么办?哈哈哈,所以说我们有办法嘛: 定义deepv为v点的深度,设两个要求lca的点分别为a,b,且deepa >= deep

[luogu3379]最近公共祖先(树上倍增求LCA)

题意:求最近公共祖先. 解题关键:三种方法,1.st表 2.倍增法 3.tarjan 此次使用倍增模板 #include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> #include<cmath> using namespace std; typedef long long ll; int n,m,root,cnt

倍增求LCA

LCA:(Least Common Ancestors),即最近公共祖先节点. 1 const int maxn = 100003; 2 const int maxl = 19; 3 4 struct Edge { 5 int t; 6 Edge *ne; 7 }; 8 9 int dep[maxn], up[maxn][maxl]; 10 Edge *head[maxn]; 11 12 void DFS(int u) { 13 for (int i = 1; i < maxl; ++ i) {

CF 519E(树上倍增求lca)

传送门:A and B and Lecture Rooms 题意:给定一棵树,每次询问到达点u,v距离相等的点有多少个. 分析:按情况考虑: 1.abs(deep[u]-deep[v])%2==1时,必定不存在到达u,v距离相等的点. 2.如果deep[u]==deep[v]时,ans=n-num[lca(u,v)u在的儿子树]-num[lca(u,v)v在的儿子树]. 3.如果deep[u]!=deep[v]时,在u到v的路径中找出到达u,v相等的节点x,则ans=num[x]-num[u在的