zoukankan      html  css  js  c++  java
  • LOJ#535. 「LibreOJ Round #6」花火(最大子矩形问题+扫描线+线段树)

    https://loj.ac/problem/535

    题解:

    有点感觉这个是个经典题,我咋想不到呢。

    不交换就是逆序对数。

    考虑交换(h[x])(h[y])

    得满足(h[x]>h[y]),不然没有意义。

    那么逆序对会减少(2*sum_{x<z<y}h[x]>h[z]>h[y])

    这就相当于矩形数点问题:以((x,h[x]))为左上角,((y,h[y]))为右下角的矩形内的点数。

    注意到对一个左上角((x,h[x]))如果有((u,h[u]))满足(u<x且h[u]>h[x])

    ((u,h[u]))((x,h[x]))的左上角,既然要使矩形覆盖点数最多,那么选((u,h[u]))作为左上角一定优于((x,h[x]))

    对右下角同理。

    可能的左上角点满足(x)递增时,(h[x])下降。

    现在再考虑每个点(z),在(z)的左上角的点就是一个区间,右下角同理,这个区间可以二分出来。

    那么变成了矩形加,求最大值问题,扫描线+线段树即可。

    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int N = 3e5 + 5;
    
    int n, h[N], p[N], q[N];
    struct P {
    	int x, y, f;
    };
    vector<P> d[N];
    #define pb push_back
    
    void Init() {
    	scanf("%d", &n);
    	fo(i, 1, n) scanf("%d", &h[i]);
    	fo(i, 1, n) p[i] = max(p[i - 1], h[i]);
    	q[n + 1] = 3e5 + 1; fd(i, n, 1) q[i] = min(q[i + 1], h[i]);
    	fo(i, 1, n) {
    		int x = 0, y = n + 1;
    		for(int l = 1, r = i - 1; l <= r; ) {
    			int m = l + r >> 1;
    			if(p[m] < h[i]) x = m, l = m + 1; else r = m - 1;
    		}
    		for(int l = i + 1, r = n; l <= r; ) {
    			int m = l + r >> 1;
    			if(q[m] > h[i]) y = m, r = m - 1; else l = m + 1;
    		}
    		if(x + 1 <= i - 1 && i + 1 <= y - 1) {
    			d[x + 1].pb((P) {i + 1, y - 1, 1});
    			d[i].pb((P) {i + 1, y - 1, -1});
    		}
    	}
    }
    
    int t[N * 4], lz[N * 4];
    int pl, pr, px;
    
    #define i0 i + i
    #define i1 i + i + 1
    void pla(int i, int y) { t[i] += y, lz[i] += y;}
    void down(int i) { if(lz[i]) pla(i0, lz[i]), pla(i1, lz[i]), lz[i] = 0;}
    void add(int i, int x, int y) {
    	if(y < pl || x > pr) return;
    	if(x >= pl && y <= pr) {
    		pla(i, px); return;
    	}
    	int m = x + y >> 1; down(i);
    	add(i0, x, m); add(i1, m + 1, y);
    	t[i] = max(t[i0], t[i1]);
    }
    #define low(x) ((x) & -(x))
    
    ll ans, f[N];
    void add(int x, int y) {
    	for(; x <= 3e5; x += low(x)) f[x] += y;
    }
    ll sum(int x) {
    	ll s = 0;
    	for(; x; x -= low(x)) s += f[x];
    	return s;
    }
    
    void Work() {
    	fo(i, 1, n) {
    		ff(j, 0, d[i].size()) {
    			P v = d[i][j];
    			pl = v.x, pr = v.y, px = v.f;
    			add(1, 1, n);
    		}
    		ans = max(ans, (ll) t[1]);
    	}
    	ans = -2 * ans;
    	fo(i, 1, n) {
    		ans += sum(3e5) - sum(h[i]);
    		add(h[i], 1);
    	}
    	pp("%lld
    ", ans);
    }
    
    int main() {
    	Init();
    	Work();
    }
    
    
  • 相关阅读:
    my read map subway / metro / map / ditie / gaotie / traffic / jiaotong
    hd printer lexmark / dazifuyin / dayin / fuyin
    软件应用程序的打包和部署
    99款高质量免费(X)HTML/CSS模板
    PetShop4.0的安装、设置、调试与体验(草稿)
    山塞一个PetShop(Task000)——架构
    如何用C#开发的计算器小软件
    DIV+CSS布局参考站点
    影响计算机性能的设置
    ASP.NET知识点:母版页的路径问题
  • 原文地址:https://www.cnblogs.com/coldchair/p/12362067.html
Copyright © 2011-2022 走看看