51Nod-1562-玻璃切割

21 篇文章 0 订阅
12 篇文章 1 订阅

首先推荐这位大大的博客,我是看他的博客看懂的:
http://blog.csdn.net/f_zyj/article/details/68939756

问题描述:

现在有一块玻璃,是长方形的(w 毫米× h 毫米),现在要对他进行切割。

切割的方向有两种,横向和纵向。每一次切割之后就会有若干块玻璃被分成两块更小的玻璃。在切割之后玻璃不会被移动。

现在想知道每次切割之后面积最大的一块玻璃是多少。

样例解释:

对于第四次切割,下面四块玻璃的面积是一样大的。都是2。

Input

单组测试数据。
第一行有三个整数 w,h,n (2≤w,h≤200000, 1≤n≤200000),表示玻璃在横向上长w 毫米,纵向上长h 毫米,接下来有n次的切割。
接下来有n行输入,每一行描述一次切割。
输入的格式是H y 或 V x。
H y表示横向切割,切割线距离下边缘y毫米(1≤y≤h-1)。
V x表示纵向切割,切割线距离左边缘x毫米(1≤x≤w-1)。
输入保证不会有两次切割是一样的。

Output

对于每一次切割,输出所有玻璃中面积最大的是多少。

Input示例

样例输入1
4 3 4
H 2
V 2
V 3
V 1

Output示例

样例输出1
8
4
4
2

挺神奇的一道题,开始是用链表总,超时,然后看评论说用IO挂,多交几次有一定几率过(看人品··)。。。
这里写图片描述
然后看到网上第二种思路,用并查集来做,首先如何用并查集来表示一个区间,将点i和i+1合并,并且将他们的权值也合并,如果在某点进行了分割,就不将该点进行合并操作,然后先把每个切割线记录下来,做一次处理,得到的并查集就是对N次切割完得到的情况,接着倒着来,把每次切割的点j,与j+1进行合并操作,并合并他们的权值,同时更新最大的宽和高,再把答案存起来,最后输出。

#include<bits/stdc++.h>
using namespace std;
const long long maxn=2e5+10;

long long mx[2];
long long par[2][maxn];
long long rankpar[2][maxn];
long long vis[2][maxn];
vector<pair<char,long long> >input;

long long w,h,n;

long long find(long long k,long long z)
{
    return par[z][k]=(par[z][k]==k?k:find(par[z][k],z));
}

void join(long long x,long long y,long long z)
{
    long long xx=find(x,z);
    long long yy=find(y,z);
    par[z][xx]=yy;
    rankpar[z][yy]+=rankpar[z][xx];
    mx[z]=max(mx[z],rankpar[z][yy]);
}

void init()
{
    for(long long i=0;i<2;i++)
    {
        for(long long j=0;j<maxn;j++)
        {
            par[i][j]=j;
            rankpar[i][j]=1;
        }
    }
}

int main()
{
    cin>>w>>h>>n;
    memset(vis,0,sizeof(vis));
    pair<char,long long> p;
    mx[0]=mx[1]=1;
    init();
    for(long long i=0;i<n;i++)
    {
        getchar();
        p.first=getchar();
        scanf("%d",&p.second);
        input.push_back(p);
        if(p.first=='H')
         vis[0][p.second]=1;
        else
         vis[1][p.second]=1;
    }
    for(long long i=1;i<h;i++)
    {
        if(!vis[0][i])
            join(i,i+1,0);
    }
    for(long long i=1;i<w;i++)
    {
        if(!vis[1][i])
            join(i,i+1,1);
    }
    stack<long long> ans;
    ans.push(mx[0]*mx[1]);
    for(long long i=n-1;i>=0;i--)
    {
        if(input[i].first=='H')
            join(input[i].second,input[i].second+1,0);
        else
            join(input[i].second,input[i].second+1,1);
        ans.push(mx[0]*mx[1]);
    }
    ans.pop();
    while(!ans.empty())
    {
        cout<<ans.top()<<endl;
        ans.pop();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值