题解 CF1795F 【Blocking Chips】

· · 题解

题目大意

题解

正向考虑不方便,因为我们无法确定一个点到底应该向上走更优还是向下走更优。但是如果我们知道一个点需要移动多少步,就会好解决得多。

假设我们已知每个点的目标步数,那么可以任选一点作为根节点,对树进行 dfs,对于每个节点,统计这个节点向下走至多能走多少步。

在递归返回时,如果当前节点有棋子,就进行如下判断:

优先向下走的贪心一定是正确的,因为递归返回时,一定是按照深度从大到小处理,即走到当前节点时,其子树中没有棋子,或者子树中的棋子都已经达成要求,而向下走只会影响子树中的节点,而对未处理的节点没有影响,所以能向下走时,向下走一定最优。

显然步数越多,要求越难以实现,二分答案即可。

时间复杂度 O(n \log n)

代码:

#include<bits/stdc++.h>
using namespace std;
template<typename T>
void read(T &res) {
    res=0;bool f=false;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=true; ch=getchar();}
    while(ch>='0'&&ch<='9') res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    res=f?-res:res;
}
template<typename T,typename ...Args>
void read(T &res,Args &...args) {read(res); read(args...);}
template<typename T>
void write(T x) {if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0');}
template<typename T>
inline void writeln(T x) {write(x);putchar('\n');}
template<typename T,typename ...Args>
void write(T x,Args ...args) {write(x); putchar(' '); write(args...);}
template<typename T,typename ...Args>
void writeln(T x,Args ...args) {write(x); putchar('\n'); writeln(args...);}
#define MAXN 200001
class Edge {
public:
    Edge() {
        to=next=len=0;
    }
    int to,next,len;
};
class Graph {
public:
    Graph() {
        memset(g,0,sizeof(g));
        memset(head,0,sizeof(head));
        tot=0;
    }
    inline void clear(int n) {
        memset(head,0,sizeof(int)*(n+1));
        memset(g,0,sizeof(Edge)*(tot+1));
        tot=0;
    }
    inline void addEdge(int from,int to,int len) {
        g[++tot].to=to;g[tot].next=head[from];g[tot].len=len;head[from]=tot;
        g[++tot].to=from;g[tot].next=head[to];g[tot].len=len;head[to]=tot;
    }
    Edge g[MAXN<<1];
    int head[MAXN],tot;
}g;
int n,k,need[MAXN],dep[MAXN],a[MAXN];
bool vis[MAXN];
bool dfs(int u,int fa) {
    dep[u]=0;
    for(int i=g.head[u];i;i=g.g[i].next) {
        int v=g.g[i].to;
        if(v==fa) continue;
        if(!dfs(v,u)) return false;
        if(!vis[v]) dep[u]=max(dep[u],dep[v]+1);
    }
    if(dep[u]>=need[u]) {
        return true;
    }
    if(dep[u]<need[u]) {
        if(!fa||vis[fa]) return false;
        vis[fa]=true;
        need[fa]=need[u]-1;
        need[u]=0;
    }
    return true;
}
inline bool check(int len) {
    memset(vis,0,sizeof(bool)*(n+1));
    memset(need,0,sizeof(int)*(n+1));
    vis[0]=1;
    for(int i=1;i<=k;i++) {
        need[a[i]]=len/k;
        vis[a[i]]=true;
    }
    for(int i=1;i<=len%k;i++) {
        ++need[a[i]];
    }
    return dfs(1,0);
}
inline void solve() {
    read(n);
    for(int i=1;i<n;i++) {
        int u=0,v=0;
        read(u,v);
        g.addEdge(u,v,1);
    }
    read(k);
    for(int i=1;i<=k;i++) {
        read(a[i]);
    }
    int l=0,r=n,res=0;
    while(l<=r) {
        int mid=(l+r)>>1;
        if(check(mid)) {
            res=mid;
            l=mid+1;
        } else {
            r=mid-1;
        }
    }
    g.clear(n);
    writeln(res);
}
int main() {
    int T=0;
    read(T);
    while(T--) solve();
    return 0;
}