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. k8s开启cadvisor http 服务

    k8s开启cadvisor http 服务 cadvisor介绍: Google的 cAdvisor 是另一个知名的开源容器监控工具. 只需在宿主机上部署cAdvisor容器,用户就可通过Web界面或 ...

  2. ubuntu go 开发环境搭建

    访问:https://golang.org/dl/ 下载 go1.12.4.linux-amd64.tar.gz wget https://dl.google.com/go/go1.12.4.linu ...

  3. CDC类介绍

    CDC类 中文介绍 CDC类定义的是设备上下文对象的类. CDC对象提供处理显示器或打印机等设备上下文的成员函数,以及处理与窗口客户区对应的显示上下文的成员. 通过CDC对象的成员函数进行所有的绘图. ...

  4. Redis客户端信息的存取

    字符串的存: set name xxx 字符串的取: get name Hashes的存: HMSET xxx xxx xxx Hashes的取: HGETALL xxx Lists的存: lpush ...

  5. web题

    @php绕过https://www.cnblogs.com/leixiao-/p/9786496.html @step1:F12 step2:抓包 @任何url  http://118.25.14.4 ...

  6. idea、eclipse常用快捷键

    idea常用快捷键 Ctrl+Shift + Enter,语句完成“!”,否定完成,输入表达式时按 “!”键Ctrl+E,最近的文件Ctrl+Shift+E,最近更改的文件Shift+Click,可以 ...

  7. ASP.NET Core EFCore 之DBFirst 自动创建实体类和数据库上下文

    通过引用Nuget包添加实体类 运行 Install-Package Microsoft.EntityFrameworkCore.SqlServer 运行 Install-Package Micros ...

  8. 如何重装mysql8及初次修改密码

    首先在设置里卸载旧版的mysql 然后把你之前的安装的mysql文件夹整个删掉 然后删除注册表的MySQL信息 安装新版的MySQL 新建并配置my-default.ini文件 如下: [mysqld ...

  9. 2. zookeeper介绍及集群搭建

    ZooKeeper 概述 Zookeeper 是一个分布式协调服务的开源框架. 主要用来解决分布式集群中 应用系统的一致性问题,例如怎样避免同时操作同一数据造成脏读的问题. ZooKeeper 本质上 ...

  10. vc_redist x64 或者x86下载地址

    https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads 微软的东西,果然还是人 ...