Codeforces 527C 线段树 /set

20 篇文章 0 订阅
19 篇文章 0 订阅

题目:http://codeforces.com/problemset/problem/527/C

题意:

给出矩形的长和高,然后给出一些操作,水平或者竖直切割矩形,每切割一次,求出剩下的面积最大的矩形

分析:

看到题目,就想到是如何维护区间的最大值,第一想到的就是线段树,可以把还可以划线点的用1表示,划了线的用0表示,然后求最大长度就是如何求连续的1的最大个数,那么这题的变成了一道区间合并的问题了。那这道题集合hdu3667有点相似了,我的题解hdu 3667 ,区间合并需要注意的就是点和长度的区别,注意最后要加1.

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long ll;
const int N=2e5+5;
int lsum[N<<2][2],rsum[N<<2][2],sum[N<<2][2]; //分别维护区间左侧开始最多连续1的个数,右侧,和整个区间
bool pure[N<<2][2]; //标记是否整个区间都是连续1,其实这个数组不必要,只是为了方便
int t[2];
void pushUP(int rt,int id)
{
    pure[rt][id]=pure[rt<<1][id]&&pure[rt<<1|1][id];
    sum[rt][id]=max(rsum[rt<<1][id]+lsum[rt<<1|1][id],max(sum[rt<<1][id],sum[rt<<1|1][id]));
    lsum[rt][id]=pure[rt<<1][id]?lsum[rt<<1][id]+lsum[rt<<1|1][id]:lsum[rt<<1][id];
    rsum[rt][id]=pure[rt<<1|1][id]?rsum[rt<<1|1][id]+rsum[rt<<1][id]:rsum[rt<<1|1][id];
}
void build(int l,int r,int rt,int id)
{
    if(l==r){
        if(l==0)return;
        lsum[rt][id]=rsum[rt][id]=sum[rt][id]=pure[rt][id]=1;
        return;
    }
    int m=(l+r)>>1;
    build(lson,id);
    build(rson,id);
    pushUP(rt,id);
}
void update(int l,int r,int rt,int id,int p)
{
    if(l==r&&l==p){
        pure[rt][id]=sum[rt][id]=lsum[rt][id]=rsum[rt][id]=0;
        return;
    }
    int m=(l+r)>>1;
    if(p<=m)update(lson,id,p);
    else update(rson,id,p);
    pushUP(rt,id);
}
int main()
{
    //freopen("f.txt","r",stdin);
    int w,h,n;
    scanf("%d%d%d",&w,&h,&n);
    build(0,w-1,1,0);
    build(0,h-1,1,1);
    char op[5];
    int p;
   // cout<<sum[1][0]<<' '<<sum[1][1]<<endl;
    while(n--){
        scanf("%s%d",op,&p);
        op[0]=='V'?update(0,w-1,1,0,p):update(0,h-1,1,1,p);
        //cout<<sum[1][0]<<' '<<sum[1][1]<<endl;
        printf("%I64d\n",(ll)(sum[1][0]+1)*(ll)(sum[1][1]+1));
    }
    return 0;
}

线段树的非递归写法可参考这篇博客,我还是第一次见,不好理解啊 http://blog.csdn.net/zearot/article/details/44759437

然而这题还有更多的人使用set和multiset去维护,挺简单的,学习一下。

#include<iostream>
#include<cstdio>
#include<set>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
set<int>::iterator i,j;
set<int>sw,sh;
multiset<int>msw,msh;
void update(set<int>&s,multiset<int>&ms,int p)
{
    s.insert(p);
    i=j=s.find(p);
    --i;++j;
    ms.erase(ms.find(*j-*i)); //要这样删除一个元素
   // ms.erase(*j-*i);  //这样会把值相等的所有元素全删掉
    ms.insert(p-*i);
    ms.insert(*j-p);
}
int main()
{
    //freopen("f.txt","r",stdin);
    int ww,hh,n;
    scanf("%d%d%d",&ww,&hh,&n);
    sw.insert(0);sw.insert(ww);
    sh.insert(0);sh.insert(hh);
    msw.insert(ww);
    msh.insert(hh);
    char op[5];
    int p;
    while(n--){
        scanf("%s%d",op,&p);
        if(op[0]=='V'){
            update(sw,msw,p);
            printf("%I64d\n",(ll)*(--msw.end())*(ll)(*(--msh.end())));
        }
        else{
            update(sh,msh,p);
            printf("%I64d\n",(ll)(*(--msw.end()))*(ll)(*(--msh.end())));
        }
//        for(multiset<int>::iterator it=msw.begin();it!=msw.end();it++)
//            cout<<*it<<' ';
//        cout<<endl;
    }
    return 0;
}


Input

The first line contains three integers w, h, n (2 ≤ w, h ≤ 200 000,1 ≤ n ≤ 200 000).

Next n lines contain the descriptions of the cuts. Each description has the formH y or V x. In the first case Leonid makes the horizontal cut at the distancey millimeters (1 ≤ y ≤ h - 1) from the lower edge of the original sheet of glass. In the second case Leonid makes a vertical cut at distancex (1 ≤ x ≤ w - 1) millimeters from the left edge of the original sheet of glass. It is guaranteed that Leonid won't make two identical cuts.

Output

After each cut print on a single line the area of the maximum available glass fragment in mm2.

Examples
Input
4 3 4
H 2
V 2
V 3
V 1
Output
8
4
4
2
Input
7 6 5
H 4
V 3
V 5
H 2
V 1
Output
28
16
12
6
4
Note

Picture for the first sample test:

Picture for the second sample test:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值