热身训练1 ping ping ping

点此进入

题意:

一棵树,n+1 个节点,以0号节点为根,给出端点(a,b),节点a到节点b的路径上,至少有一个点是“坏掉的”,求“坏掉的点”最少

分析:

Step1:贪心

每次给出的两个端点,我们可以得到他俩的lca,画一下图我们即可知道,lca深度越深,下面的点就越需要单独选一下,并且选了之后,对lca在上面的点影响不大

同时,我们每次选一段路径上的点时,肯定选深度较低的,这样最优

Step2:线段树标记选过的点

我们选过的节点,那么它的子树我们都可以不用选了

用DFS序+线段树,标记。

easy~~~

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define LL long long
const int N=30005, M=50005;
int tt, las[N], nt[M], ed[M];
inline void add(const int x, const int y)
{
    ed[++tt]=y; nt[tt]=las[x]; las[x]=tt;
}
int dep[N], in[N], ou[N], fa[N][25], total;
void DFS(const int x, const int FA)
{
    dep[x]=dep[FA]+1;
    in[x]=++total;
    fa[x][0]=FA;
    for(re i=1;i<=20;++i) fa[x][i] = fa[fa[x][i-1]][i-1];
    for(re i=las[x];i;i=nt[i])
    {
        int v=ed[i];
        if(v != FA)
        {
            DFS(v, x);    
        }
    }
    ou[x]=total;
}
inline int lca(int x,int y)
{
    if(dep[x] < dep[y]) swap(x, y);
    int del = (dep[x] - dep[y]);
    for(re i=0;i<=20;++i) if(del&(1<<i)) x = fa[x][i];
    if(x == y) return x;
    for(re i=20;i >= 0;--i)
    if(fa[x][i] != fa[y][i])
    x = fa[x][i], y = fa[y][i];
    return fa[x][0];
}
int n, m, ans;
struct rdin{int a, b, ca;}ask[50005];
bool cmp(const rdin&x, const rdin&y)
{
    return dep[x.ca] > dep[y.ca];
}
struct segment{int a, b, v;}tr[N<<3];
inline void build(const int p, const int x, const int y)
{
    tr[p]=(segment){x, y, 0};
    if(x != y)
    {
        int mid=(x+y)>>1;
        build(p<<1, x, mid);
        build(p<<1|1, mid+1, y);
    }
}
void modi(const int p, const int x, const int y)
{
    if(x <= tr[p].a && tr[p].b <= y)
    {
        tr[p].v = 1;
        return;
    }
    int mid=(tr[p].a+tr[p].b)>>1;
    if(x <= mid) modi(p<<1, x, y);
    if(y > mid) modi(p<<1|1, x, y);
    
    tr[p].v = (tr[p<<1].v && tr[p<<1|1].v);
}
int query(const int p, const int x)
{
    if(tr[p].v == 1) 
    {
        return 1;
    }
    if(tr[p].a == x && x == tr[p].b)
    {
        return tr[p].v;
    }
    int mid=(tr[p].a+tr[p].b)>>1;
    if(x <= mid) return query(p<<1, x);
    else return query(p<<1|1, x);
}
signed main()
{
    while(scanf("%d",&n) != EOF)
    {
        ans = tt = total = 0;
        memset(las, 0, sizeof(las));
        
        for(re i=1;i<=n;++i)
        {
            int x, y;
            scanf("%d%d",&x,&y);
            x++; y++;
            add(x, y);
            add(y, x);
        }
        n++;
        DFS(1, 0);
        scanf("%d",&m);
        for(re i=1;i<=m;++i)
        {
            scanf("%d%d",&ask[i].a,&ask[i].b);
            ask[i].a++; ask[i].b++;
            ask[i].ca = lca(ask[i].a, ask[i].b);
        }
        sort(ask+1, ask+1+m, cmp);
        build(1, 1, n+5);
        for(re i=1;i<=m;++i)
        {
            int a=query(1, in[ask[i].a]);
            int b=query(1, in[ask[i].b]);
            if(a==0 && b==0)
            {
                modi(1, in[ask[i].ca], ou[ask[i].ca]);
                ans++;
            }
        }
        printf("%d\n", ans);    
    }
}

 

posted @ 2021-07-15 19:56  kzsn  阅读(79)  评论(0编辑  收藏  举报