CSU 2017 NCPC2016

2017: Highest Tower

Submit Page      Summary      Time Limit: 7 Sec       Memory Limit: 128 Mb       Submitted: 14       Solved: 2    

Description

Oni loved to build tall towers of blocks. Her parents were not as amused though. They were on the verge of going crazy over that annoying loud noise when- ever a tower fell to the ground, not to mention having to pick up blocks from the floor all the time. Oni’s mother one day had an idea. Instead of building the tower out of physical blocks, why couldn’t Oni construct a picture of a tower using two-dimensional rectangles that she montaged on a board on the wall?

Oni’s mother cut out rectangles of various sizes and colors, drew a horizontal line representing the ground at the bottom of the board, and explained the rules of the game to Oni: every rectangle must be placed immediately above another rectangle or the ground line. For every rectangle you can choose which of its two orientations to use. I.e., if a rectangle has sides of length s and t, you can either have a side of length s horizontally or a side of length t horizontally. You may place exactly one rectangle immediately above another one if its horizontal side is strictly smaller than the horizontal side of the rectangle beneath. Exactly one rectangle must be placed on the ground line. Now try to build as tall a tower as possible!

Oni’s mother took extra care to make sure that it was indeed possible to use all rectangles in a tower in order not to discourage Oni. But of course Oni quickly lost interest anyway and returned to her physical blocks. After all, what is the point of building a tower if you cannot feel the suspense before the inevitable collapse? Her father on the other hand got interested by his wife’s puzzle as he realized this is not a kids’ game.

Input

The first line of input contains an integer n(1n250000)n(1≤n≤250000) , the number of rectangles. Then follow n lines, each containing two integers s and t ( 1st1091≤s≤t≤109 nm), the dimensions of a rectangle. You may safely assume that there is a way to build a tower using all n rectangles.

Output

Output a single line containing the height in nm of the tallest possible tower using all the rectangles while having the horizontal side lengths strictly decreasing from bottom to top.

Sample Input

3
50000 160000
50000 100000
50000 100000

Sample Output

200000

Hint

Source

NCPC2016


题目大意:给出n个长方形的长和宽,要把他们摞起来(平面是2维的),问最大高度。要求:1、一层只能放一个长方形,即n个长方形最后要有n层;2.、所有长方形的底边长度由下至上必须严格单调递减;3、底和高的长度可以互换,通俗点讲,就是可以躺着放,也可以立起来放置;4、题目保证有解。


题解:这个题的关键是构造图论模型,需要巧妙地构图。我们规定a->b表示长方形放置时底边长为a,高度为b,同理,b->a表示长方形放置时底边长为b,高度为a。

第一步:给出的n个长方形,每个长方形的两个边长之间连接一条无向边,那么放置长方形的过程就转换成给无向边设置方向的过程。

第二步:构造出来的图有大于等于1个联通块,我们要对每个联通块分别求解。联通块只有两类,一种是边数==点的个数,一种是边数==点的个数+1。如图所示:


                                                            第一种联通块

                                            

                                                            第二种联通块



第三步:对于第一种情况,每个点有且仅有一个出度,那么点i的入度就为du[i]-1(du[i]为点i的度)。所以点i的的贡献就为 (du[i]-1)*i;对于第二种情况,只有一个点的出度可以为0,其他点有且仅有一个出度,那么哪一个点出度为0呢?我们可以先将所有点的出度规定为1,然后恢复一个点使之出度为0,那么答案就要加上恢复的点的标号,所以应该选择标号最大的点的出度为0。

第四步:对于第二种情况,如何求联通块的最大标号?最暴力的肯定是遍历整个图,但考虑到我们只关心最大值,就可以用并查集解决,在建立父子关系时,我们只需规定数大的为父亲,数小的为儿子,最后每个点的父亲都为所在联通块的最大值了。


代码:

#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<algorithm>
#define N 250010
#define pk push_back
#define LL long long
using namespace std;

int a[N],b[N],c[N<<1],du[N<<1],fa[N<<1],v[N<<1];

int getfa(int x)
{
    if (x==fa[x]) return x;else
    {
        int t=getfa(fa[x]);
        if (v[x]==1) v[t]=1;                //扩散v[i]
        fa[x]=t;
        return t;
    }
}

int main()
{
    int n,m;
    while(~scanf("%d",&n))
    {
        memset(v,0,sizeof v);memset(du,-1,sizeof du);
        for (int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i],&b[i]);
            c[i]=a[i];c[i+n]=b[i];
        }
        sort(c+1,c+n+n+1);
        m=unique(c+1,c+n*2+1)-c-1;
        for (int i=1;i<=m;i++)fa[i]=i;
        for (int i=1;i<=n;i++)
        {
            int t=lower_bound(c+1,c+m+1,a[i])-c;
            du[t]++;
            int tt=lower_bound(c+1,c+m+1,b[i])-c;
            du[tt]++;
            int p=getfa(t),q=getfa(tt);
            if (p==q) v[p]=1;else if (p>q) fa[q]=p;else fa[p]=q;          //v[p]==1 表示p所在的联通块属于第一种情况,因为出现了环
        }
        LL ans=0;
        for(int i=1;i<=m;i++) getfa(i);       //必须要先过一遍,这是为了使第一种情况的联通块的v[i]都为1
        for(int i=1;i<=m;i++) ans+=(LL) c[i]*du[i];
        for(int i=1;i<=m;i++)
        {
            int t=getfa(i);
            if (!v[t])
            {
                ans+=c[t];
                v[t]=1;
            }
        }
        printf("%lld\n",ans);
    }
}

/**********************************************************************
	Problem: 2017
	User: songpengyu
	Language: C++
	Result: AC
	Time:500 ms
	Memory:10884 kb
**********************************************************************/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值