zoukankan      html  css  js  c++  java
  • POI2014

    ...一个shabi和一堆神题的故事

    今天只写了两道

    之后随缘更吧

    啊 顺便 snake我是不会更的

    bzoj3829 POI2014 Farmcraft

    mhy住在一棵有n个点的树的1号结点上,每个结点上都有一个妹子。
    mhy从自己家出发,去给每一个妹子都送一台电脑,每个妹子拿到电脑后就会开始安装zhx牌杀毒软件,第i个妹子安装时间为Ci。
    树上的每条边mhy能且仅能走两次,每次耗费1单位时间。mhy送完所有电脑后会回自己家里然后开始装zhx牌杀毒软件。
    卸货和装电脑是不需要时间的。
    $n leq 500000$
    求所有妹子和mhy都装好zhx牌杀毒软件的最短时间。
     
    sol:一开始对着样例江了半天...然后发现妹子是可以自己装杀毒软件的
    这就非常的简单了,状态还是设$f[x]$表示在$x$子树里安装好花费的时间,初始化...就是$f[x] = c[x]$
    然后我们看转移的顺序,显然是可以贪心的
    如果一个子树安装的比较久,我们就可以先搞它然后让它等着比较快的
    具体地,对于两个子树$u$,$v$
    当先走$u$再走$v$的时候时间是$f[u] + 1 + 2 imes size[u] + f[v] + 1$
    当先走$u$再走$v$的时候时间是$f[v] + 1 + 2 imes size[v] + f[u] + 1$
     
    这样如果$f[u] - 2 imes size[u] > f[v] - 2 imes size[v]$
    我们会选择先走$u$
    这样就可以对子树进行一下排序
    细节:最后安装$1$号节点
    #include<bits/stdc++.h>
    using namespace std;
     
    inline int read()
    {
        int x = 0,f = 1;char ch = getchar();
        for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
        for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
        return x * f;
    }
    int n;
    const int maxn = 500010;
    int first[maxn],to[maxn << 1],nx[maxn << 1],cnt;
    int val[maxn],size[maxn],fa[maxn];
    int f[maxn];
    int sons[maxn];
    inline void add(int u,int v){to[++cnt] = v;nx[cnt] = first[u];first[u] = cnt;}
    inline bool cmp(int u,int v){return max(f[u],2 * size[u] + f[v]) < max(f[v],2 * size[v] + f[u]);}
    inline void dfs(int x)
    {
        size[x] = 1;
        for(int i=first[x];i;i=nx[i])
        {
            if(to[i] == fa[x])continue;
            fa[to[i]] = x;dfs(to[i]);size[x] += size[to[i]];
        }
        int nt = 0,tmp = 0;
        f[x] = val[x];
        for(int i=first[x];i;i=nx[i]){if(to[i] == fa[x])continue;sons[++nt] = to[i];}
        sort(sons + 1,sons + nt + 1,cmp);
        for(int i=1;i<=nt;++i)f[x]=max(f[x],tmp*2+f[sons[i]]+1),tmp+=size[sons[i]];
    }
    int main()
    {
        n = read();
        for(int i=1;i<=n;i++)val[i] = read();
        for(int i=1;i<n;i++)
        {
            int u = read(),v = read();
            add(u,v);add(v,u);
        }
        dfs(1);
        cout<<max(f[1],(n-1)*2+val[1]);
    }
    
    View Code

    bzoj3832 Rally

    一个DAG,每条边长度都是$1$,求删掉一个点之后最长路的最小值

    输出最小值和那个点

    $n leq 500000$

    $m leq 2 imes n$

    sol:神题

    首先我们建超级源$S$,超级汇$T$,每个点向源汇连边$(S -> X -> T)$

    这样图上最长链就变成了$S$到$T$最长链

    我们可以拓扑序$dp$出每个点到$S$到$T$的最长链$f[x]$和$g[x]$

    这样就是对一个割集内的每条边$(x,y)$求$f[x] + g[y]$的最大值

    我们另所有点都在$T$集,$S$在$S$集

    每次从$T$删一个点加入$S$

    删除的时候删掉它的入边 记录答案 然后加入它的出边

    具体 我们要加入一个元素 删除一个元素 查询最大值

    这个用堆或者线段树都可以

    #include<bits/stdc++.h>
    using namespace std;
    inline int read()
    {
        int x = 0,f = 1;char ch = getchar();
        for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
        for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
        return x * f;
    }
    int n,m;
    const int maxn = 500010;
    struct Graph
    {
        int first[maxn],to[maxn << 1],nx[maxn << 1],cnt;
        int ind[maxn],indd[maxn];
        inline void add(int u,int v){to[++cnt] = v;nx[cnt] = first[u];first[u] = cnt;ind[v]++;indd[v]++;}
    }G,rev;
    priority_queue<int> q1,q2;
    queue<int> q;
    int dp[maxn],f[maxn];
    inline void push(int x){q1.push(x);}
    inline void del(int x){q2.push(x);while(!q1.empty() && !q2.empty() && (q1.top() == q2.top()))q1.pop(),q2.pop();}
    inline int top(){if(q1.empty())return 0;return q1.top();}
    void toposort()
    {
        for(int i=1;i<=n;i++)
            if(G.ind[i] == 0)q.push(i);
        while(!q.empty())
        {
            int now = q.front();q.pop();
            for(int i=G.first[now];i;i=G.nx[i])
            {
                G.ind[G.to[i]]--;
                dp[G.to[i]] = max(dp[G.to[i]],dp[now] + 1);
                if(G.ind[G.to[i]] == 0)q.push(G.to[i]);
            }
        }
        while(!q.empty())q.pop();
        for(int i=1;i<=n;i++)
            if(rev.ind[i] == 0)q.push(i);
        while(!q.empty())
        {
            int now = q.front();q.pop();
            for(int i=rev.first[now];i;i=rev.nx[i])
            {
                rev.ind[rev.to[i]]--;
                f[rev.to[i]] = max(f[rev.to[i]],f[now] + 1);
                if(rev.ind[rev.to[i]] == 0)q.push(rev.to[i]);
            }
        }
    }
    void solve()
    {
        int ans = (n << 1),id;
        while(!q.empty())q.pop();
        for(int i=1;i<=n;i++)
            if(G.indd[i] == 0)q.push(i);
        while(!q.empty())
        {
            int now = q.front();q.pop();
            del(f[now]);
            for(int i=rev.first[now];i;i=rev.nx[i])del(dp[rev.to[i]] + f[now] + 1);
            if(top() < ans)
            {
                ans = top();
                id = now;
            }
            for(int i=G.first[now];i;i=G.nx[i])
            {
                push(f[G.to[i]] + dp[now] + 1);
                G.indd[G.to[i]]--;
                if(G.indd[G.to[i]] == 0)q.push(G.to[i]);
            }
            push(dp[now]);
        }
        printf("%d %d",id,ans);
    }
    int main()
    {
        n = read();m = read();
        for(int i=1;i<=m;i++){int u = read(),v = read();G.add(u,v);rev.add(v,u);}
        toposort();
        for(int i=1;i<=n;i++)push(f[i]);
        solve();
         
    }
    View Code
  • 相关阅读:
    IM 融云 之 初始化及登录
    IM 融云 之 安装cocoapods 安装 SDK
    github desktop 下载
    iOS 架构模式
    IM 融云 之 通讯能力库API
    IM 融云 之 开发基础概念
    IM 之 融云
    php获得文件的属性
    js模拟复制
    linux修改yum源
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/9527157.html
Copyright © 2011-2022 走看看