zoukankan      html  css  js  c++  java
  • [codeforces 528]A. Glass Carving

    [codeforces 528]A. Glass Carving

    试题描述

    Leonid wants to become a glass carver (the person who creates beautiful artworks by cutting the glass). He already has a rectangular wmm  ×  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?

    输入

    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.

    输出

    After each cut print on a single line the area of the maximum available glass fragment in mm2.

    输入示例

    4 3 4
    H 2
    V 2
    V 3
    V 1

    输出示例

    8
    4
    4
    2

    数据规模及约定

    见“输入

    题解

    不难发现对于任意的长、宽,我们都可以还原出原玻璃板上的一个矩形,所以求最大面积可以转化为分别求最大的长和宽,然后乘起来就是答案。

    问题变成了一个一维的:每次在 [0, n] 这个区间内插入不重复的点并询问最长的不包含任何点的线段。不难想到平衡树,因为它可以维护一个点的前驱和后继(不妨设这是平衡树 1 号),那么如何实时维护最长线段呢?我们可以再建一棵平衡树(平衡树 2 号)维护每条线段的长度,那么一次插入操作(插入点 x)不仅要在 1 号中插入一个数并找到其前驱 l 和后继 r,还要在 2 号中删除 r - l 这个长度,并添加 x - l 和 r - x 这两个长度,维护最大值即可。因为要分别维护矩形的长和宽,所以总共要建立 4 棵平衡树。(感觉好有毒。。。)

    对于其他人,这题是 STL 水题;对于我,这题是数据结构码农题。。。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 1000010
    #define LL long long
    int n, m, q;
    
    struct Node {
    	int v, r, mn, mx;
    	Node(): v(0), r(0), mn(0), mx(0) {}
    	Node(int _, int __, int ___, int ____): v(_), r(__), mn(___), mx(____) {}
    } ns[maxn];
    int r1, r2, r3, r4, ch[maxn][2], fa[maxn], ToT;
    void maintain(int o) {
    	int l = ch[o][0], r = ch[o][1];
    	ns[o].mn = ns[o].mx = ns[o].v;
    	if(l) ns[o].mn = min(ns[o].mn, ns[l].mn), ns[o].mx = max(ns[o].mx, ns[l].mx);
    	if(r) ns[o].mn = min(ns[o].mn, ns[r].mn), ns[o].mx = max(ns[o].mx, ns[r].mx);
    	return ;
    }
    void rotate(int u) {
    	int y = fa[u], z = fa[y], l = 0, r = 1;
    	if(ch[y][1] == u) swap(l, r);
    	if(z) ch[z][ch[z][1]==y] = u;
    	fa[u] = z; fa[y] = u; fa[ch[u][r]] = y;
    	ch[y][l] = ch[u][r]; ch[u][r] = y;
    	maintain(y); maintain(u);
    	return ;
    }
    int xl, xr;
    void insert(int& o, int v) {
    	if(!o) ns[o = ++ToT] = Node(v, rand(), v, v);
    	else {
    		int d = (v >= ns[o].v);
    //		printf("%d %d %d
    ", ns[o].v, v, ns[ch[o][d]].mn);
    //		printf("%d %d %d
    ", ns[ch[o][d]].mx, v, ns[o].v);
    		if(v >= ns[o].v && v <= ns[ch[o][d]].mn) xl = max(xl, ns[o].v), xr = min(xr, ns[ch[o][d]].mn);
    		if(v <= ns[o].v && v >= ns[ch[o][d]].mx) xl = max(xl, ns[ch[o][d]].mx), xr = min(xr, ns[o].v);
    		insert(ch[o][d], v);
    		fa[ch[o][d]] = o;
    //		printf("bo: %d %d
    ", o, ch[o][d]);
    		if(ns[ch[o][d]].r > ns[o].r) {
    			int t = ch[o][d];
    			rotate(ch[o][d]);
    			o = t;
    		}
    //		printf("ao: %d
    ", o);
    	}
    	return maintain(o);
    }
    bool del(int& o, int v, int pa) {
    	if(!o) return 1;
    //	printf("del: %d %d %d
    ", o, ns[o].v, v);
    	if(ns[o].v == v) {
    		if(!ch[o][0] && !ch[o][1]) {
    			fa[o] = ch[o][0] = ch[o][1] = 0, o = 0;
    			maintain(o);
    			return 0;
    		}
    		if(!ch[o][0]) {
    			int t = ch[o][1];
    			fa[o] = ch[o][0] = ch[o][1] = 0, o = t, fa[o] = pa;
    			maintain(o);
    			return 0;
    		}
    		if(!ch[o][1]) {
    			int t = ch[o][0];
    			fa[o] = ch[o][0] = ch[o][1] = 0, o = t, fa[o] = pa;
    			maintain(o);
    			return 0;
    		}
    		int d = ns[ch[o][1]].r > ns[ch[o][0]].r;
    		int t = ch[o][d];
    		rotate(ch[o][d]);
    		o = t;
    		del(ch[o][d^1], v, o);
    		maintain(o);
    		return 0;
    	}
    	int d = (v >= ns[o].v);
    	if(del(ch[o][d], v, o)) maintain(o), del(ch[o][d^1], v, o);
    	maintain(o);
    	return 0;
    }
    
    int main() {
    	srand(6);
    	n = read(); m = read(); q = read();
    	
    	insert(r1, 0); insert(r1, m);
    	insert(r2, 0); insert(r2, n);
    	insert(r3, m); insert(r4, n);
    	while(q--) {
    		char tp = getchar();
    		while(!isalpha(tp)) tp = getchar();
    		int x = read();
    		xl = -1; xr = max(n, m) + 1;
    		if(tp == 'H') {
    			insert(r1, x);
    			int l = xl, r = xr;
    //			printf("f %d %d
    ", l, r);
    			del(r3, r - l, 0);
    			insert(r3, x - l), insert(r3, r - x);
    		}
    		if(tp == 'V') {
    			insert(r2, x);
    			int l = xl, r = xr;
    //			printf("f %d %d
    ", l, r);
    			del(r4, r - l, 0);
    			insert(r4, x - l), insert(r4, r - x);
    		}
    		printf("%I64d
    ", (LL)ns[r3].mx * ns[r4].mx);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    GridView 应用貌似是个mm写的,值得尊敬!
    .net 时间函数
    .net 获取url的方法
    SaveGraphics
    asp网站页面上都是问号
    由于编码方式导致CSS样式表失效
    .net url乱码
    常用正则表达式
    解决realse版在加载toolbar后不正常退出的现象
    general error c1010070: Failed to load and parse the manifest
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5810598.html
Copyright © 2011-2022 走看看