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. SAP EXCEL OLE常用方法和属性

    1.创建application: CREATE OBJECT excel 'EXCEL.APPLICATION'. 2.设置显示模式,为1前台运行,为0时表示为后台运行. . 3.设置为不弹消息框(在 ...

  2. Golang中基础的命令行模块urfave/cli

    前言相信只要部署过线上服务,都知道启动参数一定是必不可少的,当你在不同的网络.硬件.软件环境下去启动一个服务的时候,总会有一些启动参数是不确定的,这时候就需要通过命令行模块去解析这些参数,urfave ...

  3. swoole前置基础知识 进程间通信

    进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息. IPC的方式通常有管道(包括无名管道和命名管道).消息队列.信号量.共享存储.Socket ...

  4. vim简单题练习-------出自《鸟哥的linux私房菜》第309页码题目

    用vim打开文件,在第34行向右移动15字符,怎么做? 34G 15->或者15j 如何到达文件的页首或者页尾? 1G或者gg G 如何在光标所在行中,移动到行头及行尾? home end vi ...

  5. 【AMADM】django-braces -- Django的一些可重用的,通用型的mixin

    动机 简介 个人评分 动机 Django1.8以后加入了Class Based View,以及GenericView概念.之后在django对类的使用更加频繁. 而一些特性,相信我们都有重复地编写过. ...

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

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

  7. [Python3] 037 函数式编程 装饰器

    目录 函数式编程 之 装饰器 Decrator 1. 引子 2. 简介 3. 使用 函数式编程 之 装饰器 Decrator 1. 引子 >>> def func(): ... pr ...

  8. 21天学通Python课后实验题4.6

    21天学通Python课后实验题4.6 1. 编程实现用户输入一门课程的两门子课程成绩,第一门子课程60分以上,则显示“通过”,第一门子课程不及格,则显示“未通过”,第一门子课程及格,而第二门子课程不 ...

  9. 12306 的架构也太 "牛X" 了吧!

    每到节假日期间,一二线城市返乡.外出游玩的人们几乎都面临着一个问题:抢火车票! 虽然现在大多数情况下都能订到票,但是放票瞬间即无票的场景,相信大家都深有体会.尤其是春节期间,大家不仅使用12306,还 ...

  10. C++11智能指针原理和实现

    一.智能指针起因 在C++中,动态内存的管理是由程序员自己申请和释放的,用一对运算符完成:new和delete. new:在动态内存中为对象分配一块空间并返回一个指向该对象的指针: delete:指向 ...