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. springboot中静态属性/静态方法从YAML(yml)读取配置属性

    启动类添加注解@EnableConfigurationProperties import jnetman.session.SnmpPref; import org.springframework.bo ...

  2. FSCalendar使用和注意事项

    相信大家项目中或多或少都有日历这一块的内容吧,公司作为教育行业的软件公司,当然也是一定有的. 最近被日历这一块的内容弄得很头疼啊,改来改去的,不过还是学到了很多东西,至少FSCalendar的使用基本 ...

  3. WPF 非UI线程更新UI界面的各种方法小结

    转载:https://www.cnblogs.com/bdbw2012/articles/3777594.html 我们知道只有UI线程才能更新UI界面,其他线程访问UI控件被认为是非法的.但是我们在 ...

  4. 如何搭建本地yum源,阿里yum源以及自己的网络yum源?

    环境:CentOS7 一.本地源的yum源的搭建 (一)添加新的yum源配置文件iso.repo(名字可以自己命名,但是后缀必须是repo结尾) 注意:目录 /etc/yum.repos.d 下的 . ...

  5. Linux C/C++基础——文件(上)

    1.文件指针 FILE* fp=NULL; fp指针,只调用了fopen(),在堆区分配空间,把地址返回给fp fp指针不是指向文件,fp指针和文件关联,fp内部成员保存在文件的状态 操作fp指针,不 ...

  6. python基础之列表list

    list常用命令:索引/切片:list[index] list[start_index:end_index]增:list.append(obj) list.insert(index,obj) list ...

  7. Java学习-4

    面向对象的三大特征之一:继承性 主要解决问题:共性抽取 继承关系当中的特点:子类可以拥有父类的“内容”,子类还可以拥有自己专属的内容 定义一个父类的格式(就是定义一个普通类的格式): Public c ...

  8. Nginx linux下的安装

    1.先把从官网 nginx.io下载 的安装包通过ftp传到服务器上,然后进行解压. 我的安装环境以及nginx版本 :Ubuntu16 ,nginx-1.11.3.tar.gz(经过这个尝试这个版本 ...

  9. table表格的无缝循环

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. Robot Framework(三)项目实践出现的问题以及解决方法

    导航: 1.元素定位失败 2.系统自带的确认弹窗 3.ElementNotVisibleException: Message: element not visible 1.元素定位失败(使用frame ...