Codeforces 527C 線段樹 /set

題目: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:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章