您的位置:首页 > 其它

Codeforces 527C 线段树 /set

2016-03-05 22:52 489 查看
题目: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:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: