码迷,mamicode.com
首页 > 其他好文 > 详细

Aizu 2456 Usoperanto

时间:2015-10-02 18:35:23      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:

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

技术分享

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

数据最多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\n",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\n",ans);
    return 0;
}

 

Aizu 2456 Usoperanto

标签:

原文地址:http://www.cnblogs.com/jerryRey/p/4852428.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!