Codeforces Round #798(Div.2)

https://codeforces.com/contest/1689

C

题意:给定一棵以 \(1\) 为根,\(n\) 个节点的二叉树,根节点被感染了。然后将会执行以下过程 \(n\) 次:

  • 选定一个未被感染的节点,删除它,断开它周围的所有连边。
  • 已感染的节点会沿其连边感染其相邻节点。

求最后最多可以有多少个节点未被感染(删除的节点不算)

分析:裸树形dp,\(dp[x]\) 表示 \(x\) 刚刚被感染,最多可以解救其子树内的多少个节点。

#include<bits/stdc++.h>
using namespace std;
#define f(i, a, b) for(int i = a; i <= b; i++)
#define mod9 998244353
#define mod1 1000000007
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define endl '\n'
int n;
vector<vector<int>> g;
vector<int> sz;
vector<int> dp;
void dfs1(int x, int fa){
    int nowsz=1;
    f(i, 0, (int)g[x].size()-1){
        if(g[x][i] != fa) {
            dfs1(g[x][i], x);
            nowsz += sz[g[x][i]];
        }
    }
    sz[x] = nowsz;
}
void dfs2(int x, int fa) {
    if(g[x].size() == 1 && x != 1) return;
    if((g[x].size() == 2&&x!=1) || (g[x].size()==1&&x==1)) {
        f(i,0,(int)g[x].size()-1){
            if(g[x][i]!=fa){
                dfs2(g[x][i],x);
                dp[x]=sz[g[x][i]]-1;
            }
        }
        return;
    }
    if(g[x].size() == 3 || (g[x].size()==2&&x==1)) {
        int lson=0,rson=0;
        f(i,0,(int)g[x].size()-1){
            if(g[x][i]!=fa){
                if(!lson) lson=g[x][i]; else rson=g[x][i];
                dfs2(g[x][i],x);
            }
        }
        dp[x]=max(sz[lson]-1+dp[rson],sz[rson]-1+dp[lson]);
        return;
    }   
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    int t;cin>>t;
    while(t--){
        cin>>n;
        g.clear(); g.resize(n + 10);
        sz.clear(); sz.resize(n + 10);
        dp.clear(); dp.resize(n + 10);
        int ans = 0;
        f(i,1,n-1){
            int u, v; cin >> u >> v;
            g[u].push_back(v); g[v].push_back(u); 
        }
        dfs1(1, 0);
        dfs2(1, 0);
        cout << dp[1] << endl;
    }
    return 0;
}

启发:考试的时候想了一个奇怪的 \(dp\),遇到树还是想树形 \(dp\)(子节点上传到父节点)。

D

题意:给定 \(n \times m\) 的黑白网格图,求一个点,使得这个点到所有黑点曼哈顿距离的最大值最小。

\(n,m \le 1000,\sum nm \le 10^6\)

分析:本题的关键是发现黑点里只有几个点是对答案产生贡献的。
\(i\) 到黑点 \(j\) 的曼哈顿距离公式:
\(x_i+y_i-x_j-y_j\)
\(x_i-y_i+x_j-y_j\)
\(-x_i+y_i-x_j+y_j\)
\(-x_i-y_i+x_j+y_j\)
分别对应 \(j\)\(i\) 的四种方向。
对于一个点,如果只考虑其左上方的点,那么只有 \(-x_j-y_j\) 最大的点是产生答案贡献的黑点。如果考虑其他方向和其他点,类似。
那么对我们的答案有贡献的点是 \(-x_j-y_j,x_j-y_j,-x_j+y_j,x_j+y_j\) 分别最大的点,最多有 \(4\) 个。
暴力比较即可。
时间复杂度 \(O(nm)\)

posted @ 2022-06-11 11:45  OIer某罗  阅读(81)  评论(0)    收藏  举报