題目: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;
}
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.
After each cut print on a single line the area of the maximum available glass fragment in mm2.
4 3 4 H 2 V 2 V 3 V 1
8 4 4 2
7 6 5 H 4 V 3 V 5 H 2 V 1
28 16 12 6 4
Picture for the first sample test: