zoukankan      html  css  js  c++  java
  • Aizu 2456 Usoperanto (贪心)

    贪心,对于一个修饰关系可以连一条有向边,在合并的时候,子节点的序列一定是连续安排的,因为如果有交叉,交换以后一定更优。

    然后一个序列一个序列的考虑,长度短的应该在前面,否则同样交换以后更优。因此排序以后统计就行了。

    数据理论最多递归1e6层,dfs爆栈了,手写栈模拟递归。。。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e6+5;
    
    vector<int> G[maxn];
    int M[maxn];
    typedef long long ll;
    long long ans;
    bool cmp(int a,int b) { return M[a] < M[b]; }
    
    struct Frame
    {
        int u,i;
    };
    stack<Frame> dfs;
    inline void CreatFrame(int u){ dfs.push({u,0});}
    
    #define PS push
    void DFS(int s)
    {
        CreatFrame(s);
        bool pre = true;//pre or post
        while(dfs.size()){
            loop:
            int u = dfs.top().u, &i = dfs.top().i;
            for(; i < (int)G[u].size(); i++){
                if(pre) {
                    CreatFrame(G[u][i]);
                    goto loop;
                }
                M[u] += M[G[u][i]];
                pre = true;
            }
            sort(G[u].begin(),G[u].end(),cmp);
            for(int i = 0; i < (int)G[u].size(); i++){
                ans += M[G[u][i]]*((ll)G[u].size()-i-1);
            }
            dfs.pop(); pre = false;
        }
    }
    int rts[maxn];
    
    //#define LOCAL
    int main()
    {
    #ifdef LOCAL
        freopen("in.txt","r",stdin);
    #endif
        int n; scanf("%d",&n);
        int c = 0;
        for(int i = 0; i < n; i++){
            int f; scanf("%d%d",M+i,&f);
            if(~f){ G[f].push_back(i); }
            else rts[c++] = i;
        }
        while(c--){
            DFS(rts[c]);
        }
        printf("%lld
    ",ans);
        return 0;
    }

    另外拓扑排序也可以避免递归

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e6+5;
    
    int hd[maxn],nx[maxn],to[maxn],ec;
    
    void add(int u,int v)
    {
        nx[++ec] = hd[u];
        to[ec] = v;
        hd[u] = ec;
    }
    
    int M[maxn];
    int fa[maxn],deg[maxn];
    
    typedef long long ll;
    
    int stk[maxn];
    int q[maxn];
    
    //#define LOCAL
    int main()
    {
    #ifdef LOCAL
        freopen("in.txt","r",stdin);
    #endif
        int n; scanf("%d",&n);
        int rt = 0;
        for(int i = 0; i < n; i++){
            int f; scanf("%d%d",M+i,&f);
            if(~f){
                add(f,i); deg[f]++;
            }
            fa[i] = f;
        }
        int frnt = 0, tail = 0;
        for(int i = 0; i < n; i++){
            if(!deg[i]) q[tail++] = i;
        }
        long long ans = 0;
        while(frnt<tail){
            int u = q[frnt++];
            int top = 0;
            for(int i = hd[u]; i; i = nx[i]){
                stk[top++] = M[to[i]];
            }
            sort(stk,stk+top);
            for(int i = 0; i < top; i++){
                ans += stk[i]*(ll)(top-i-1);
            }
            if(~fa[u]){
                M[fa[u]] += M[u];
                if(!--deg[fa[u]])  q[tail++] = fa[u];
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    60阶单群同构于A5的证明
    Riemann映射定理
    一个特殊情形的Mittag-Leffler分解
    一个重要的函数
    指数有限的子群存在一个右陪集代表元系,同时也是左陪集代表元系
    素数的平方阶群必为Abel群
    $mathscr{F}$类
    一个多项式问题
    Mittag-Leffler定理,Weierstrass因子分解定理和插值定理
    C -Concatenating Teams (字符串hash)
  • 原文地址:https://www.cnblogs.com/jerryRey/p/4852428.html
Copyright © 2011-2022 走看看