zoukankan      html  css  js  c++  java
  • CF #629 Div.3 E(LCA)F

    E

    题意:给定一棵n个点的树,问是否能找到一条路径,使k个点要么在路径上,要么距路径长度为1。

    分析:LCA

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<string>
    #include<iostream>
    #include<set>
    #include<map>
    #include<stack>
    #include<queue>
    #include<vector>
    #include<sstream>
    typedef long long LL;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    const int MAXN = 200000 + 10;
    const int LOG_MAXN = 18;
    const double eps = 1e-8;
    int dcmp(double a, double b){
        if(fabs(a - b) < eps) return 0;
        return a < b ? -1 : 1;
    }
    vector<int> G[MAXN];
    int depth[MAXN];
    int parent[LOG_MAXN][MAXN];
    int n, m;
    vector<int> V;
    void dfs(int v, int p, int d){
        depth[v] = d;
        parent[0][v] = p;
        int len = G[v].size();
        for(int i = 0; i < len; ++i){
            if(G[v][i] != p){
                dfs(G[v][i], v, d + 1);
            }
        }
    }
    void init(){
        dfs(1, -1, 0);
        for(int k = 0; k + 1 < LOG_MAXN; ++k){
            for(int v = 1; v <= n; ++v){
                if(parent[k][v] == -1) parent[k + 1][v] = -1;
                else{
                    parent[k + 1][v] = parent[k][parent[k][v]];
                }
            }
        }
    }
    bool cmp(const int &a, const int &b){
        return depth[a] < depth[b];
    }
    int lca(int u, int v){
        if(depth[u] > depth[v]){
            swap(u, v);
        }
        for(int k = 0; k < LOG_MAXN; ++k){
            if((depth[u] - depth[v]) >> k & 1){
                v = parent[k][v];
            }
        }
        if(u == v) return u;
        for(int k = LOG_MAXN - 1; k >= 0; --k){
            if(parent[k][u] != parent[k][v]){
                u = parent[k][u];
                v = parent[k][v];
            }
        }
        return parent[0][u];
    }
    int main(){
        scanf("%d%d", &n, &m);
        int x, y;
        for(int i = 0; i < n - 1; ++i){
            scanf("%d%d", &x, &y);
            G[x].push_back(y);
            G[y].push_back(x);
        }
        init();
        while(m--){
            int k;
            scanf("%d", &k);
            V.clear();
            while(k--){
                scanf("%d", &x);
                V.push_back(x);
            }
            sort(V.begin(), V.end(), cmp);
            int len = V.size();
            bool ok = true;
            for(int i = 1; i < len; ++i){
                int tmp = lca(V[i], V[i - 1]);
                if(depth[V[i]] - depth[tmp] > 1 && depth[V[i - 1]] - depth[tmp] > 1){
                    ok = false;
                    break;
                }
            }
            if(ok) printf("YES
    ");
            else printf("NO
    ");
        }
        return 0;
    }
    

    F

    题意:有n个点,允许进行两种操作:(1)将最小的数加1(2)将最大的数减一,问最少操作几次,可以得到k个相等的数。

    分析:遍历枚举答案取最小值。可以只取左边,只取右边,两边都取。

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<string>
    #include<iostream>
    #include<set>
    #include<map>
    #include<stack>
    #include<queue>
    #include<vector>
    #include<sstream>
    typedef long long LL;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    const int MAXN = 200000 + 10;
    const double eps = 1e-8;
    int dcmp(double a, double b){
        if(fabs(a - b) < eps) return 0;
        return a < b ? -1 : 1;
    }
    LL a[MAXN], pre[MAXN], suf[MAXN];
    map<LL, LL> l, r;
    int main(){
        LL n, k;
        scanf("%lld%lld", &n, &k);
        for(LL i = 1; i <= n; ++i){
            scanf("%lld", &a[i]);
        }
        sort(a + 1, a + n + 1);
        for(LL i = 1; i <= n; ++i){
            pre[i] = pre[i - 1] + a[i];
            if(!l[a[i]]){
                l[a[i]] = i;
            }
        }
        for(LL i = n; i >= 1; --i){
            suf[i] = suf[i + 1] + a[i];
            if(!r[a[i]]) r[a[i]] = i;
        }
        LL ans = 1000000000000000;
        for(LL i = 1; i <= n; ++i){
            LL cnt = r[a[i]] - l[a[i]] + 1;
            if(cnt >= k){
                ans = 0;
                break;
            }
            LL cost1, cost2;
            cost1 = (a[i] - 1) * (i - 1) - pre[i - 1];
            cost2 = suf[r[a[i]] + 1] - (a[i] + 1) * (n - r[a[i]]);
            if(cnt + i - 1 >= k){
                ans = min(ans, cost1 + k - cnt);
            }
            if(cnt + n - r[a[i]] >= k){
                ans = min(ans, cost2 + k - cnt);
            }
            ans = min(ans, cost1 + cost2 + k - cnt);
            i += cnt - 1;
        }
        printf("%lld
    ", ans);
        return 0;
    }
    

      

  • 相关阅读:
    HDU 5861 Road (线段树)
    HDU 5857 Median (推导)
    HDU 5858 Hard problem (数学推导)
    HDU 5867 Water problem (模拟)
    UVALive 7455 Linear Ecosystem (高斯消元)
    A bug about RecipientEditTextView
    当Activity出现Exception时是如何处理的?
    FontSize sp 和 dp 的区别
    Android的Overlay机制
    关于控件问题的分析
  • 原文地址:https://www.cnblogs.com/tyty-Somnuspoppy/p/12585038.html
Copyright © 2011-2022 走看看