HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:【http://acm.hdu.edu.cn/showproblem.php?pid=6203】

题意  :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点。

题解  :求每个点对的LCA,然后根据LCA的深度排序。从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1。

#include<Bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int N, Q;
int c[maxn], In[maxn], Out[maxn], cnt;
struct Edge
{
    int id, next;
    Edge(int id = 0, int next = 0): id(id), next(next) {}
} E[maxn << 1]; //双向边
int head[maxn], tot;
void initEdge()
{
    memset(c, 0, sizeof(c));
    cnt = 0;
    for(int i = 0; i <= N; i++) head[i] = -1;
    tot = 0;
}
void addEdge(int u, int v)
{
    E[tot] = Edge(v, head[u]);
    head[u] = tot++;
}
int siz[maxn], top[maxn], dep[maxn], fa[maxn];
int clk;//需要初始化
void DFS1(int u, int p)
{
    In[u] = ++cnt;
    dep[u] = dep[p] + 1;
    fa[u] = p, siz[u] = 1;
    for(int k = head[u]; k != -1; k = E[k].next)
    {
        int id = E[k].id;
        if(id == p) continue;
        DFS1(id, u);
        siz[u] += siz[id];
    }
    Out[u] = cnt;
}
void DFS2(int u, int p)
{
    int son = -1;
    for(int k = head[u]; k != -1; k = E[k].next)//找重儿子
    {
        int id = E[k].id;
        if(id == p)continue;
        if(son == -1 || siz[id] > siz[son]) son = id;
    }
    if(son != -1)
    {
        top[son] = top[u];
        DFS2(son, u);
    }
    for(int k = head[u]; k != -1; k = E[k].next)
    {
        int id = E[k].id;
        if(id == p || id == son)continue;
        top[id] = id;
        DFS2(id, u);
    }
}
int LCA(int x, int y)
{
    while(top[x] != top[y])
    {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    return x;
}

struct node
{
    int u, v, lca;
    bool operator < (const node &T) const
    {
        return dep[lca] > dep[T.lca];
    }
} qry[50050];
int low_Bit(int x)
{
    return x & -x;
}
void update(int x, int val)
{
    while(x <= N)
    {
        c[x] += val;
        x += low_Bit(x);
    }
}
int get_sum(int x)
{
    int ret = 0;
    while(x > 0)
    {
        ret += c[x];
        x -= low_Bit(x);
    }
    return ret;
}
int main()
{
    while(~scanf("%d", &N))
    {
        N++;
        initEdge();
        for(int i = 1; i <= N - 1; i++)
        {
            int u, v;
            scanf("%d %d", &u, &v);
            u++, v++;
            addEdge(u, v), addEdge(v, u);
        }
        DFS1(1, 0),top[1] = 1,DFS2(1, 0);
        scanf("%d", &Q);
        for(int i = 1; i <= Q; i++)
        {
            scanf("%d %d", &qry[i].u, &qry[i].v);
            qry[i].u++, qry[i].v++;
            qry[i].lca = LCA(qry[i].u, qry[i].v);
        }
        sort(qry + 1, qry + 1 + Q);
        int ans = 0;
        for(int i = 1; i <= Q; i++)
        {
            int u = qry[i].lca;
            int ret = get_sum(In[qry[i].u]) + get_sum(In[qry[i].v]);
            if(ret) continue;
            ans++;
            update(In[u], 1);
            update(Out[u] + 1, -1);
        }
        printf("%d\n", ans);
    }
    return 0;
}

  

时间: 2024-08-01 14:12:55

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]的相关文章

HDU 5156 - Harry and Christmas tree (dfs序+离线树状数组)

http://acm.hdu.edu.cn/showproblem.php?pid=5156 BC#25的C题. 题意是:给出一颗大小为n的树,以1为根,然后给出m次染色,每次将节点u加上一种颜色(一个节点可以有多个颜色). 最后查询树上每个节点对应子树上包含的不同颜色数量. 当时这场比赛没有做,回来看一下题目,没看标解就试着敲了一遍,于是解题思路从一开始就走上了不归路. 标解是O(n+m)的方法,主要思路是将问题转为:一次染色表示将u到根节点的路径都染上这种颜色. 但这样做需要去重,因为如果u

【BZOJ1103】大都市meg(DFS序,树状数组)

题意:有一颗树,1号点为根,保证编号小的点深度较小,初始状态每条边都没有被标记,要求实现两个操作在线: A:将连接x,y的边标记 W:查询从1到x的路径上有多少条边未被标记 n<=2*10^5 思路:本题的特殊性质: 1.一次只标记一条边且没有重边 2.直接求1到x的路径,不用LCA 记录i点在DFS序中第一次与最后一次出现的时间b[i]与c[i] 可以发现若(x,y)(x<y)边被标记只对区间(b[y],c[y])有1的贡献 等价于前缀和s[b[y]]++ s[c[y]+1]-- 至于s[c

【Tyvj2133 BZOJ1146】网络管理Network(树套树,DFS序,树状数组,主席树,树上差分)

题意:有一棵N个点的树,每个点有一个点权a[i],要求在线实现以下操作: 1:将X号点的点权修改为Y 2:查询X到Y的路径上第K大的点权 n,q<=80000 a[i]<=10^8 思路:此题明显地体现了我对主席树理解不深 树上路径K大可以直接用树剖+二分答案+树做 但DFS序+主席树也可以 对于点U,它能影响DFS序上的区间(st[u],ed[u]) 所以维护方法就是类似序列K大一样 s[st[u]]++ s[ed[u]+1]-- 对于路径(x,y),信息为s[x]+s[y]-s[lca(x

HDOJ5877(dfs序+离散化+树状数组)

Weak Pair Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 2081    Accepted Submission(s): 643 Problem Description You are given a rooted tree of N nodes, labeled from 1 to N. To the ith node a

HDU 5618:Jam&#39;s problem again(CDQ分治+树状数组处理三维偏序)

http://acm.hdu.edu.cn/showproblem.php?pid=5618 题意:-- 思路:和NEUOJ那题一样的.重新写了遍理解了一下,算作处理三维偏序的模板了. 1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 using namespace std; 6 #define INF 0x3f3f3f3f 7 #d

Apple Tree POJ - 3321 dfs序列构造树状数组(好题)

There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. Kaka likes apple very much, so he has been carefully nurturing the big apple tree. The tree has N forks which are connected by branches. Kaka numbers

hdu 5775 Bubble Sort(2016 Multi-University Training Contest 4——树状数组)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5775 Bubble Sort Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 636    Accepted Submission(s): 378 Problem Description P is a permutation of the

hdu 5249区间第k大(学习了下树状数组的搞法)

KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 205    Accepted Submission(s): 70 Problem Description 你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了很大的知名度.数十亿的请求被推到一个大管道后同时服务从管头拉取请求.让我们来定义每个请求都有一个重要值.我的K

HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形dp, 对于每条链u,v,w,我们只在lca(u,v)的顶点上处理它 让dp[i]表示以i为根的指数的最大值,sum[i]表示dp[vi]的和(vi为i的儿子们) 则i点有两种决策,一种是不选以i为lca的链,则dp[i]=sum[i]. 另一种是选一条以i为lca的链,那么有转移方程:dp[i]=

HDU 5458 Stability(双连通分量+LCA+并查集+树状数组)(2015 ACM/ICPC Asia Regional Shenyang Online)

题目大意:给一个N个点M条边的无向图,有Q个询问:1.删掉a.b之间所存在的边:2.询问有多少条边,单独删掉之后a与b不再连通. 思路:脑洞大开. 对于询问,首先想到的就是a与b之间有多少桥(割边),然后想到双连通分量,然而删边是个坑爹的问题,于是我们离线倒着来,把删边变成加边. 双连通分量这种东西呢,其实缩点连起来之后,就是一棵树辣. 然后询问两个点的时候,设根到点x的距离为dep[x],a.b的最近公共祖先为lca(a, b),那么询问query(a, b) = dep[a] + dep[b