Live2d Test Env

BZOJ4886: [Lydsy1705月赛]叠塔游戏(环套树森林&贪心)

4886: [Lydsy1705月赛]叠塔游戏

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 198  Solved: 76
[Submit][Status][Discuss]

Description

小Q正在玩一个叠塔的游戏,游戏的目标是叠出尽可能高的塔。在游戏中,一共有n张矩形卡片,其中第i张卡片的
长度为a_i,宽度为b_i。小Q需要把所有卡片按一定顺序叠成一座塔,要求对于任意一个矩形,它的长度要严格大
于它上边的任意一个矩形的长度。塔的高度为所有矩形的宽度之和。在游戏中,小Q可以将卡片翻转90度来使用,
而且必须用上全部n张卡片。请写一个程序,帮助计算小Q能叠出最高的塔的高度。

Input

第一行包含一个正整数n(1<=n<=250000),即卡片的个数。
接下来n行,每行两个正整数a_i,b_i(1<=a_i,b_i<=10^9),分别表示每张卡片的长度和宽度。

Output

输出一行一个整数,即最高的塔的高度,输入数据保证一定存在解。

Sample Input

3
5 16
10 5
5 10

Sample Output

20

HINT

Source

 

思路:要求长度递增,求最大宽度之和。 由于排序是自己定的,所以只要求长度不相同,求最大宽度之和。 这样的话,我们就尝试用最大费用流来建图,

S向每个矩形连(1,0)(表示容量为1,费用为0)的边;     每个矩形向x连(1,y)的边,向y连(1,x)的边;     然后每个数向T连(1,0)的边。然后就是跑最大费用流。 由于数据太大,显然会超时。  这样的题一般可以贪心优化,可以对比bzoj4883,是一个套路。

此题的定向和bzoj4883的定向不一样,此题的定向会决定答案的大小。  只有无环的连通块,根的贡献=度数,其他都是=度数-1。 所以此题不需要排序,只需要找连通块的最大值即可。

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=500010;
int N,cnt,ma,sum,tot,a[maxn],b[maxn],fa[maxn],tag[maxn];
int val[maxn],d[maxn],mx[maxn],Laxt[maxn],To[maxn],Next[maxn];
map<int,int>idx; bool vis[maxn];ll ans;
void add(int u,int v){ d[u]++;To[++cnt]=v;Next[cnt]=Laxt[u];Laxt[u]=cnt;}
int find(int x){
    if(x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}
int main(){
   int u,v; scanf("%d",&N);
   rep(i,1,N){
      scanf("%d%d",&u,&v);
      if(!idx[u]) idx[u]=++tot,val[tot]=u;
      if(!idx[v]) idx[v]=++tot,val[tot]=v;
      u=idx[u]; v=idx[v]; d[u]++; d[v]++;
      a[i]=u; b[i]=v;
   }
   rep(i,1,tot) fa[i]=i,mx[i]=val[i];
   rep(i,1,tot){
        int x=find(a[i]),y=find(b[i]);
        if(tag[x]&&tag[y]) continue;
        if(x==y) tag[x]=1;
        else fa[y]=x,tag[x]|=tag[y],mx[x]=max(mx[x],mx[y]);
   }
   rep(i,1,tot){
       ans+=(ll)(d[i]-1)*val[i];
       if(find(i)==i&&!tag[i]) ans+=mx[i];
   }
   printf("%lld",ans);
   return 0;
}

 

posted @ 2018-11-18 15:37  nimphy  阅读(307)  评论(0编辑  收藏  举报