C. Glass Carving

time limit per test2 seconds

memory limit per test256 megabytes

inputstandard input

outputstandard output

Leonid wants to become a glass carver (the person who creates beautiful artworks by cutting the glass). He already has a rectangular w mm  ×  h mm sheet of glass, a diamond glass cutter and lots of enthusiasm. What he lacks is understanding of what to carve and how.

In order not to waste time, he decided to practice the technique of carving. To do this, he makes vertical and horizontal cuts through the entire sheet. This process results in making smaller rectangular fragments of glass. Leonid does not move the newly made glass fragments. In particular, a cut divides each fragment of glass that it goes through into smaller fragments.

After each cut Leonid tries to determine what area the largest of the currently available glass fragments has. Since there appear more and more fragments, this question takes him more and more time and distracts him from the fascinating process.

Leonid offers to divide the labor — he will cut glass, and you will calculate the area of the maximum fragment after each cut. Do you agree?

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 form H y or V x. In the first case Leonid makes the horizontal cut at the distance y 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 distance x (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

inputCopy

4 3 4

H 2

V 2

V 3

V 1

outputCopy

8

4

4

2

inputCopy

7 6 5

H 4

V 3

V 5

H 2

V 1

outputCopy

28

16

12

6

4

Note

Picture for the first sample test:

Picture for the second sample test:

题意:

给你一个矩阵,和q个询问,每个询问可以横着切或者竖着切,问你切之后剩下完整的的矩阵中面积最大的是多大?

思路:

线段树可以维护最长连续0.

我们可以按行和列建立2个线段树,

点的信息为0或者1,0代表没有被切,1代表已经被切。

,每一次查询行和列的最大连续0,行列加1后乘起来即是最大的矩阵面积。

为什么要加1?

我们01序列表示的是每一个点是否被切割,而矩阵转成点线的问题可以这样处理:

即有n行每一行m列小方块,那么转成点线(方便线段树处理)就建立为 1~n-1 行,1~m-1列

查询的时候+1 就是方格个数。

接下来我们看如何用线段树维护区间最长连续零的个数。

我们每一个区间维护这四个信息:

1、从左开始最长的连续零个数 (记为 Rnum)

2、从右开始最长连续零个数 ( 记为 Lnum)

3、区间最长连续零的个数、(记为num)

4、本区间是否全为0 (其实可以用3与区间的长度判断得出,但是多维护一个减少代码量。)

从儿子节点更新父节点:

1、从左开始最长连续零的个数:

如果左儿子全是0,则为左儿子的num+ 右儿子的Lnum

否则为 左儿子的Lnum

2、从右开始最长连续零的个数:

如果右儿子全是0,则为右儿子的num+ 左儿子的Rnum

否则为 右儿子的Rnum

3、区间最长连续零的个数:

max(左儿子的Lnum,右儿子的Rnum,左儿子的Rnum+右儿子的Lnum )

4、本区间是否全为0

最容易维护,判断左右儿子是否都全为0即可。

细节见代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;}
inline void getInt(int* p);
const int maxn = 200200;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
struct node
{
int l,r;
int isall;
int num;
int lm;
int rm;
};
node segment_tree1[maxn<<2];
node segment_tree2[maxn<<2];
void pushup(node * segment_tree,int rt)
{
if(segment_tree[rt<<1].isall)
{
segment_tree[rt].isall=(segment_tree[rt<<1|1].isall);
segment_tree[rt].num=segment_tree[rt<<1].lm+segment_tree[rt<<1|1].lm;
segment_tree[rt].lm=segment_tree[rt<<1].lm+segment_tree[rt<<1|1].lm;
if(segment_tree[rt<<1|1].isall)
{
segment_tree[rt].rm=segment_tree[rt<<1|1].num+segment_tree[rt<<1].rm;
}else
{
segment_tree[rt].rm=segment_tree[rt<<1|1].rm;
}
}else if(segment_tree[rt<<1|1].isall)
{
segment_tree[rt].isall=(segment_tree[rt<<1].isall);
segment_tree[rt].num=segment_tree[rt<<1|1].rm+segment_tree[rt<<1].rm;
segment_tree[rt].rm=segment_tree[rt<<1|1].rm+segment_tree[rt<<1].rm;
if(segment_tree[rt<<1].isall)
{
segment_tree[rt].lm=segment_tree[rt<<1|1].num+segment_tree[rt<<1].lm;
}else
{
segment_tree[rt].lm=segment_tree[rt<<1].lm;
}
}else
{
segment_tree[rt].isall=0;
segment_tree[rt].lm=segment_tree[rt<<1].lm;
segment_tree[rt].rm=segment_tree[rt<<1|1].rm;
segment_tree[rt].num=max(max(segment_tree[rt].lm,segment_tree[rt].rm),segment_tree[rt<<1].rm+segment_tree[rt<<1|1].lm);
segment_tree[rt].num=max(segment_tree[rt].num,segment_tree[rt<<1].num);
segment_tree[rt].num=max(segment_tree[rt].num,segment_tree[rt<<1|1].num);
} }
void build(node * segment_tree,int rt,int l,int r)
{
segment_tree[rt].l=l;
segment_tree[rt].r=r;
if(l==r)
{
segment_tree[rt].isall=1;
segment_tree[rt].lm=1;
segment_tree[rt].rm=1;
segment_tree[rt].num=1;
return;
}
int mid=(l+r)>>1;
build(segment_tree,rt<<1,l,mid);
build(segment_tree,rt<<1|1,mid+1,r);
pushup(segment_tree,rt);
}
int ask(node * segment_tree)
{
return segment_tree[1].num;
}
void update(node * segment_tree,int rt,int x)
{
if(segment_tree[rt].l==segment_tree[rt].r&&segment_tree[rt].l==x)
{
segment_tree[rt].isall=0;
segment_tree[rt].lm=0;
segment_tree[rt].rm=0;
segment_tree[rt].num=0;
}else
{
int mid=(segment_tree[rt].l+segment_tree[rt].r)>>1;
if(x<=mid)
{
update(segment_tree,rt<<1,x);
}else
{
update(segment_tree,rt<<1|1,x);
}
pushup(segment_tree,rt);
}
} int main()
{
//freopen("D:\\code\\text\\input.txt","r",stdin);
//freopen("D:\\code\\text\\output.txt","w",stdout);
int n,m;
int q;
scanf("%d %d %d",&n,&m,&q);
build(segment_tree1,1,1,m-1);
build(segment_tree2,1,1,n-1);
while(q--)
{
char op;
getchar();
scanf("%c",&op);
if(op=='H')
{
int x;
scanf("%d",&x);
update(segment_tree1,1,x);
}else
{
int x;
scanf("%d",&x);
update(segment_tree2,1,x);
}
ll ans=(ask(segment_tree2)+1ll);
ans*=(ask(segment_tree1)+1ll);
printf("%lld\n",ans );
}
return 0;
} inline void getInt(int* p) {
char ch;
do {
ch = getchar();
} while (ch == ' ' || ch == '\n');
if (ch == '-') {
*p = -(getchar() - '0');
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 - ch + '0';
}
}
else {
*p = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 + ch - '0';
}
}
}

Glass Carving CodeForces - 527C (线段树)的更多相关文章

  1. Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论

    Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论 题意 给你一段数,然后小明去猜某一区间内的gcd,这里不一定是准确值,如果在这个区间内改变 ...

  2. Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem E (Codeforces 831E) - 线段树 - 树状数组

    Vasily has a deck of cards consisting of n cards. There is an integer on each of the cards, this int ...

  3. Codeforces 938G 线段树分治 线性基 可撤销并查集

    Codeforces 938G Shortest Path Queries 一张连通图,三种操作 1.给x和y之间加上边权为d的边,保证不会产生重边 2.删除x和y之间的边,保证此边之前存在 3.询问 ...

  4. codeforces 1136E 线段树

    codeforces 1136E: 题意:给你一个长度为n的序列a和长度为n-1的序列k,序列a在任何时候都满足如下性质,a[i+1]>=ai+ki,如果更新后a[i+1]<ai+ki了, ...

  5. Z - New Year Tree CodeForces - 620E 线段树 区间种类 bitset

    Z - New Year Tree CodeForces - 620E 这个题目还没有写,先想想思路,我觉得这个题目应该可以用bitset, 首先这个肯定是用dfs序把这个树转化成线段树,也就是二叉树 ...

  6. D - The Bakery CodeForces - 834D 线段树优化dp···

    D - The Bakery CodeForces - 834D 这个题目好难啊,我理解了好久,都没有怎么理解好, 这种线段树优化dp,感觉还是很难的. 直接说思路吧,说不清楚就看代码吧. 这个题目转 ...

  7. B - Legacy CodeForces - 787D 线段树优化建图+dij最短路 基本套路

    B - Legacy CodeForces - 787D 这个题目开始看过去还是很简单的,就是一个最短路,但是这个最短路的建图没有那么简单,因为直接的普通建图边太多了,肯定会超时的,所以要用线段树来优 ...

  8. CodeForces 343D 线段树维护dfs序

    给定一棵树,初始时树为空 操作1,往某个结点注水,那么该结点的子树都注满了水 操作2,将某个结点的水放空,那么该结点的父亲的水也就放空了 操作3,询问某个点是否有水 我们将树进行dfs, 生成in[u ...

  9. Linear Kingdom Races CodeForces - 115E (线段树优化dp)

    大意: n条赛道, 初始全坏, 修复第$i$条花费$a_i$, m场比赛, 第$i$场比赛需要占用$[l_i,r_i]$的所有赛道, 收益为$w_i$, 求一个比赛方案使得收益最大. 设$dp[i]$ ...

随机推荐

  1. Linux Shell 中 > 和 >> 的异同点和应用场景

    Linux Shell 中 > 和 >> 的异同点和应用场景 > 和 >> 的异同点 举例说明(start.sh 为某个服务的启动脚本,start.log 为某服务 ...

  2. style属性

    style加样式是加在行间,取样式也是在行间取: 我们来看下面这段代码: <!DOCTYPE HTML> <html> <head> <meta charse ...

  3. 【学习笔记】python3中csv文件使用

    1. reader=csv.reader(f, delimiter=','):按行读取数据,reader为生成器,读取的每行数据为列表格式,可以通过delimiter参数指定分隔符. import c ...

  4. 基于硬件的消息队列中间件 Solace 简介之二

    前言...... 前面简单介绍了Solace来自于哪家公司, 主要能做哪些事情. 本篇主要进一步介绍Solace作为消息传递的中间件如何工作的. 传统意义上来讲, 每当我们谈到消息中间件时, 首先想到 ...

  5. json字符串转成 json对象 json对象转换成java对象

    import com.alibaba.fastjson.JSONArray;import com.alibaba.fastjson.JSONObject; 依赖包 <dependency> ...

  6. PTA(Basic Level)1058.A+B in Hogwarts

    If you are a fan of Harry Potter, you would know the world of magic has its own currency system -- a ...

  7. [转帖]微软 SQL Server 2008/R2 停止支持

    微软 SQL Server 2008/R2 停止支持 微软停止支持 SQLSERVER 2008R2 https://t.cj.sina.com.cn/articles/view/3172142827 ...

  8. 新建项目报错'/Users/yanguobin/IdeaProjects/Demo/pom.xml' already exists in VFS

    出现该情况的原因:是删除的时候并没有删除干净,点击如下位置会清除Idea的本地代码历史,然后重新创建项目就可以了

  9. Java基础开篇

    我是一个2019毕业的非计算机的毕业生,从大二开始喜欢上Java直到现在一直都在学习,Brid从小就对计算机感兴趣,可惜高中的时候不懂事,没有规划未来,考上了一所专科学院,然后大一并不能转专业,现在毕 ...

  10. C++;STL--队列与栈;

    队列 queue模板类的定义在<queue>头文件中. queue 模板类也需要两个模板参数,一个是元素类型,一个容器类型,元素类型是必要的,容器类型是可选的,默认为deque 类型. 定 ...