4886: [Lydsy1705月赛]叠塔游戏
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 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
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; }