• NOIP 2012 疫情控制


    题目链接

    https://www.luogu.org/problemnew/show/P1084

    这个很考码力……

    写得我………………

    大致思路

    一般关于时间都有一个隐含的最大值

    然后又是最小时间

    所以就是最大值最小,二分答案

    二分出时间后

    就让每个军队尽量往上跳

    跳不到根节点就停在那了

    如果跳的到根节点,就记录到根节点还能再跳多少,按照这个值排序

    然后把还没被控制的子树记录一下

    然后按照距离排序

    然后就贪心,就是让路程剩余值最小的去覆盖子树距离最小的,这样不会浪费,

    留下剩余值大的去覆盖子树距离大的

    注意这个时候如果子树在该点跳到根节点的路径时,就直接跳回去

    关于二分答案的思路

    一般题目是从条件出发,当达到题目要求的时候可以推出答案。

    而二分答案就是从答案出发,利用条件来判断看可不可以达到题目要求。

    思维一定要换过来。

    一些细节

    (1)写递归函数的时候,不要下意识的写dfs,比如这道题的push_up函数往下的时候我就写成dfs了,而且我静态差错还没查出来

    (2)这道题可以设1的根节点为0,向上跳的时候注意判断

    (3)注意大于和不等于的区别

    (4)判断是否是叶子节点可以用一个变量来表示,不需要记录度数

    (5)二分中的check函数因为要执行很多次所以要记得初始化

    (6)写结构体的时候记得内部加分号,每次都不加……

    (7)这道题注意long long(不用也能过??)

    #include<bits/stdc++.h>
    #define REP(i, a, b) for(register int i = (a); i < (b); i++)
    #define _for(i, a, b) for(register int i = (a); i <= (b); i++)
    using namespace std;
    
    typedef long long ll;
    const int MAXN = 5e5 + 10;
    const int MAXM = 20;
    
    struct Edge{ int to, w, next; };
    Edge e[MAXN << 1];
    int head[MAXN], tot;
    
    ll dis[MAXN][MAXM + 5];
    int f[MAXN][MAXM + 5], st[MAXN];
    int vis[MAXN], n, m, cnt; 
    
    void AddEdge(int from, int to, int w)
    {
        e[tot] = Edge{to, w, head[from]};
        head[from] = tot++;
    }
    
    void read(int& x)
    {
        int f = 1; x = 0; char ch = getchar();
        while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar(); }
        while(isdigit(ch)) { x = x * 10 + ch - '0'; ch = getchar(); }
        x *= f;
    }
    
    void dfs(int u, int fa)
    {
        for(int i = head[u]; ~i; i = e[i].next)
        {
            int v = e[i].to;
            if(v == fa) continue;
            dfs(v, u);
            f[v][0] = u;
            dis[v][0] = e[i].w;
        }
    }
    
    void push_up(int u, int fa)
    {
        bool ok = 1, p = 0;
        for(int i = head[u]; ~i; i = e[i].next)
        {
            int v = e[i].to;
            if(v == fa) continue;
            push_up(v, u);
            if(!vis[v]) ok = 0;
            p = 1;
        }
        if(u != 1 && ok && p) vis[u] = 1;
    } 
    
    struct node
    { 
        int id; ll w; 
        bool operator < (const node& rhs) const
        {
            return w < rhs.w;
        }
    };
    vector<node> v1;
    vector<node> v2;
    
    bool check(ll ans)
    {
        memset(vis, 0, sizeof(vis));
        v1.clear(); v2.clear();
        
        _for(i, 1, m)
        {
            int u = st[i];
            ll dist = 0;
            for(int j = MAXM; j >= 0; j--)
                if(f[u][j] && dist + dis[u][j] <= ans)
                    dist += dis[u][j], u = f[u][j];
                    
            if(u != 1) vis[u] = 1;
            else
            {
                u = st[i];
                for(int j = MAXM; j >= 0; j--)
                    if(f[u][j] > 1) //这里是大于不是不等于 
                        u = f[u][j];
                v1.push_back(node{u, ans - dist});
            }
        }
        
        push_up(1, 0);
        for(int i = head[1]; ~i; i = e[i].next)
        {
            int v = e[i].to;
            if(!vis[v]) v2.push_back(node{v, e[i].w}); 
        } 
        
        sort(v1.begin(), v1.end());
        sort(v2.begin(), v2.end());
        
        int j = 0;
        REP(i, 0, v1.size())
        {
            if(!vis[v1[i].id]) vis[v1[i].id] = 1;
            else if(v1[i].w >= v2[j].w) vis[v2[j].id] = 1;
            while(j < v2.size() && vis[v2[j].id]) j++;
            if(j == v2.size()) return true;
        }
        return false;
    }
    
    int main()
    {
        ll l = -1, r = 0;
        memset(head, -1, sizeof(head)); tot = 0;
    
        read(n);
        REP(i, 1, n)
        {
            int u, v, w; read(u); read(v), read(w);
            AddEdge(u, v, w); AddEdge(v, u, w);
            if(u == 1 || v == 1) cnt++;
            r += w;
        }
        
        dfs(1, 0);
        f[1][0] = 0;
        _for(j, 1, MAXM)
            _for(u, 1, n)
            {
                f[u][j] = f[f[u][j-1]][j-1];
                dis[u][j] = dis[u][j-1] + dis[f[u][j-1]][j-1];
            }
        
        read(m);
        _for(i, 1, m) read(st[i]);
        if(m < cnt) { puts("-1"); return 0; }
        
        while(l + 1 < r)
        {
            int m = (l + r) >> 1;
            if(check(m)) r = m;
            else l = m;
        }
        printf("%d
    ", r);
        
        return 0;
    }
  • 相关阅读:
    Unity贴图压缩优化处理
    Unity游戏开发图片纹理压缩方案
    devexpress panelcontrol 里面控件自适应宽度
    devexpress winform spinedit 右边上下箭头去掉
    devexpress layoutcontrolitem 里面控件tabindex不起作用
    jar包生成本地maven ,以供pom引用
    C# 计算代码执行效率
    C# 使用队列
    C#遍历获取所有文件
    C#多线程等待所有子线程结束
  • 原文地址:https://www.cnblogs.com/sugewud/p/9879637.html
Copyright © 2020-2023  润新知