Codeforce gym 101741 problem C Cover the Paths 树链剖分或者set乱搞

本文介绍了一种利用树链剖分解决特定问题的方法:寻找一棵树中覆盖所有给定路径的最小节点集合。通过树链剖分优化查询过程,确保了高效的解决方案。

点我看题
18.11.14 update:
PS 四个月之后再来看这道题,发现不会写了,感觉很真实
题意 给出一颗树,然后给出m条简单路径,定义一个集合S为好集合 当且仅当对于每一条简单路径 ,都至少有一个点包含在S内。
现在要你求出大小最小的S集合 。
首先就应该往LCA的方向上去想。 将树变成一颗有向树,从最深层的LCA开始考虑。
这里要判断一条路径上是否有点已经被选取,可以用树链剖分来写。

#include<iostream>
#include<cstdio>
#include <algorithm>
#include <string.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int MAX=1e5+10;
int sum[MAX<<2];
void push_up(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int p,int l,int r,int rt){
    if(l==r){
        sum[rt]++;
        return;
    }
    int m=(l+r)>>1;
    if(m>=p){
        update(p,lson);
    }else{
        update(p,rson);
    }
    push_up(rt);
}
int query(int L,int R,int l,int r,int rt){
    if(l>=L && r<=R){
        return sum[rt];
    }
    int ans=0;
    int m=(l+r)>>1;
    if(m>=L){
        ans+=query(L,R,lson);
    }
    if(m<R){
        ans+=query(L,R,rson);
    }
    return ans;
}
class Edge{
public:
    int u,v,next;
};
int tot;
int head[MAX];
Edge edge[MAX<<1];
void add(int u,int v){
    edge[tot].u=u;
    edge[tot].v=v;
    edge[tot].next=head[u];
    head[u]=tot;
    tot++;
}
int a[MAX<<2];
int fa[MAX],top[MAX],siz[MAX],son[MAX],dep[MAX],id[MAX],rear;
void dfs1(int u,int f,int d){
    fa[u]=f,dep[u]=d;
    son[u]=0;
    siz[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v==f){
            continue;
        }
        dfs1(v,u,d+1);
        siz[u]+=siz[v];
        if(siz[son[u]]<siz[v]){
            son[u]=v;
        }
    }
}
void dfs2(int u,int tp){
    top[u] = tp;
    id[u]= ++rear;
    if(son[u]) dfs2(son[u],tp);
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v==fa[u]|| v==son[u]) continue;
        dfs2(v,v);
    }
}
void presolve(){
    rear = 0;
    dfs1(1,0,1);
    dfs2(1,1);
}
void HDL_update(int x){
    update(id[x],1,rear,1);
}
int HDL_query(int u,int v){
    int tp1= top[u];
    int tp2 = top[v];
    int sum= 0;
    while(tp1!=tp2){
        if(dep[tp1]<dep[tp2]){
            swap(u,v);
            swap(tp1,tp2);
        }
        sum+=query(id[tp1],id[u],1,rear,1);
        u=fa[tp1];
        tp1=top[u];
    }
    if(dep[u]>dep[v]) swap(u,v);
    sum+=query(id[u],id[v],1,rear,1);
    return sum;
}
int lca(int u,int v){
    int tp1=top[u],tp2=top[v];
    while(tp1!=tp2){
        if(dep[tp1]<dep[tp2]){
            swap(u,v);
            swap(tp1,tp2);
        }
        u=fa[tp1];
        tp1=top[u];
    }
    return dep[u]>dep[v]? v:u;
}
class Node{
public:
    int lca,a,b;
    bool operator < (const Node &b)const{
        return dep[lca]>dep[b.lca];
    }
};
int main(){
    memset(head,-1,sizeof head);
    int n;
    scanf("%d", &n);
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d %d",&u,&v);
        add(u,v);
        add(v,u);
    }
    presolve();
    vector<Node> V;
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        Node cnt;
        scanf("%d %d",&cnt.a,&cnt.b);
        cnt.lca=lca(cnt.a,cnt.b);
        V.push_back(cnt);
    }
    vector<int> ans;
    sort(V.begin(),V.end());
    for(int i=0;i<V.size();i++){
        Node cnt = V[i];
        if(HDL_query(cnt.a,cnt.b)>0) continue;
        ans.push_back(cnt.lca);
        HDL_update(cnt.lca);
    }
    cout<<ans.size()<<endl;
    for(int i=0;i<ans.size();i++){
        cout<<ans[i]<<" ";
    }
    return 0;
}

### Codeforces Problem or Contest 998 Information For the specific details on Codeforces problem or contest numbered 998, direct references were not provided within the available citations. However, based on similar structures observed in other contests such as those described where configurations often include constraints like `n` representing numbers of elements with defined ranges[^1], it can be inferred that contest or problem 998 would follow a comparable format. Typically, each Codeforces contest includes several problems labeled from A to F or beyond depending on the round size. Each problem comes with its own set of rules, input/output formats, and constraint descriptions. For instance, some problems specify conditions involving integer inputs for calculations or logical deductions, while others might involve more complex algorithms or data processing tasks[^3]. To find detailed information regarding contest or problem 998 specifically: - Visit the official Codeforces website. - Navigate through past contests until reaching contest 998. - Review individual problem statements under this contest for precise requirements and examples. Additionally, competitive programming platforms usually provide comprehensive documentation alongside community discussions which serve valuable resources when exploring particular challenges or learning algorithmic solutions[^2]. ```cpp // Example C++ code snippet demonstrating how contestants interact with input/output during competitions #include <iostream> using namespace std; int main() { int n; cin >> n; // Process according to problem statement specifics } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值