题目: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:
![](https://i-blog.csdnimg.cn/blog_migrate/bcdc9c1fef917cb1f66729adb6b2ce00.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6a291601dba5358407f027a28858239e.png)