1. 程式人生 > >【洛谷】P4198 樓房重建

【洛谷】P4198 樓房重建

題解

我們轉而維護每個點的斜率,顯然一個樓房能被看見它就是一個字首最大值,斜率比較為了節約精度可以用向量替代

我們每個區間維護被看到的樓房的個數,和樓房的最大值,葉子節點在有樓房時,值為1

那麼考慮合併兩個區間,左節點的所有能被看到的樓房還是能被看到,右邊節點能看到的樓房的斜率需要大於左邊節點所需要的斜率最大值
為了找到這些我們去右節點的左右區間去找
如果這個值\(P\)大於等於區間左邊的最大值,那麼這個值要在右邊找
如果小於的話,加上右邊的大小,即\(tr[u].cnt - tr[u << 1].cnt\),然後遞迴到左邊處理

複雜度\(O(n \log^2 n)\)

程式碼

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 100005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 + c - '0';
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
struct Point {
    int64 x,y;
    Point(int64 _x = 0,int64 _y = 0) {
    x = _x;y = _y;
    }
    friend Point operator + (const Point &a,const Point &b) {
    return Point(a.x + b.x,a.y + b.y);
    }
    friend Point operator - (const Point &a,const Point &b) {
    return Point(a.x - b.x,a.y - b.y);
    }
    friend int64 operator * (const Point &a,const Point &b) {
    return a.x * b.y - a.y * b.x;
    }
    friend bool operator < (const Point &a,const Point &b) {
    return a * b > 0;
    }
    friend bool operator > (const Point &a,const Point &b) {
    return a * b < 0;
    }
    friend bool operator == (const Point &a,const Point &b) {
    return a * b == 0;
    }
    friend bool operator >= (const Point &a,const Point &b) {
    return a > b || a == b;
    }
    friend bool operator <= (const Point &a,const Point &b) {
    return a < b || a == b;
    }
};
struct node {
    int L,R,cnt;Point P;
}tr[MAXN * 4];
int N,M;

void build(int u,int l,int r) {
    tr[u].L = l;tr[u].R = r;tr[u].cnt = 0;
    tr[u].P = Point(r,0);
    if(l == r) return;
    int mid = (l + r) >> 1;
    build(u << 1,l,mid);
    build(u << 1 | 1,mid + 1,r);
}
int Calc(int u,Point P) {
    if(tr[u].L == tr[u].R) return tr[u].P > P;
    if(P >= tr[u << 1].P) {
    return Calc(u << 1 | 1,P);
    }
    else {
    return Calc(u << 1,P) + tr[u].cnt - tr[u << 1].cnt;
    }
}
void Change(int u,int pos,int y) {
    if(tr[u].L == tr[u].R) {
    tr[u].P = Point(pos,y);
    if(!y) tr[u].cnt = 0;
    else tr[u].cnt = 1;
    return;
    }
    int mid = (tr[u].L + tr[u].R) >> 1;
    if(pos <= mid) Change(u << 1,pos,y);
    else Change(u << 1 | 1,pos,y);
    tr[u].P = max(tr[u << 1].P,tr[u << 1 | 1].P);
    tr[u].cnt = tr[u << 1].cnt + Calc(u << 1 | 1,tr[u << 1].P);
}
void Solve() {
    read(N);read(M);
    build(1,1,N);
    int x,y;
    for(int i = 1 ; i <= M ; ++i) {
    read(x);read(y);
    Change(1,x,y);
    out(tr[1].cnt);enter;
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}