zoukankan      html  css  js  c++  java
  • hdu 6183

    给出二维平面
    $opt1.$ 对点 $(x, y)$ 增减颜色 $c$,
    $opt2.$ 询问矩形 $(1, y_1), (x, y_2)$ 内出现过的颜色种数
    $x, y <= 1e6, c <= 50$

    二维线段树 $hehe$

    观察特殊性质每次询问的矩形的左上(下)角都在直线 $x = 1$ 上

    假设只有一种颜色
    如下平面直角坐标系

    这张图貌似并没有什么用

    给出黑色点为插入的点
    询问绿色矩形内的颜色种数
    因为假设只有 $1$ 种颜色
    所以只需判断绿色矩形内是否存在插入的点

    显然是存在的

    Sol
    每次插入一个点 $(x, y)$,把 $x$ 当做 $y$ 的权值,线段树维护每个 $y$ 的最小值
    即线段树以纵坐标 $y$ 为下标,维护每个数的最小值
    相当于单点修改 $y$ 的值为 $min(w_y, x)$
    这也就是询问的矩形左上(下)点的特殊性质所在

    这样的话
    对每个颜色开一颗线段树(动态开点)
    每次查询,枚举颜色,线段树查询区间 $(y_1, y_2)$ 内的最小值 $Min$
    如果 $Min <= $ 右上(下)点的横坐标则对答案贡献为 $1$

    时间复杂度 $O(50nlogn)$

    注意:线段树在查询时,如果当前最小值已经 $<=$ 查询的 $x$ 时,不再进行递归
    否则会 $TLE$,可能下面的code写都丑

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    const int N = 1e6 + 10;
    
    #define gc getchar()
    inline int read() {
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;    
    }
    #undef gc
    
    int Root[55], Lson[N * 4], Rson[N * 4], Minx[N * 4];
    int js_root;
    
    void Clear() {
        js_root = 0;
        memset(Root, 0, sizeof Root);
        memset(Lson, 0, sizeof Lson);
        memset(Rson, 0, sizeof Rson);
        memset(Minx, 0x3f, sizeof Minx);
    }
    
    void Poi_G(int l, int r, int &jd, int x, int num) {
        if(!jd) jd = ++ js_root;
        Minx[jd] = min(Minx[jd], num);
        if(l == r) return ;
        int mid = (l + r) >> 1;
        if(x <= mid) Poi_G(l, mid, Lson[jd], x, num);
        else Poi_G(mid + 1, r, Rson[jd], x, num);
    }
    
    int Ans;
    
    void Sec_A(int l, int r, int jd, int x, int y, int imp) {
        if(!jd || Ans <= imp) return ;
        if(x <= l && r <= y) {Ans = min(Ans, Minx[jd]); return ;}
        if(l == r) return ;
        int mid = (l + r) >> 1;
        if(x <= mid) Sec_A(l, mid, Lson[jd], x, y, imp);
        if(y > mid)  Sec_A(mid + 1, r, Rson[jd], x, y, imp);
    }
    
    int main() {
        int opt;
        memset(Minx, 0x3f, sizeof Minx);
        while(scanf("%d", &opt)) {
            if(opt == 3) break;
            else if(opt == 0) Clear();
            else if(opt == 1) {
                int x = read(), y = read(), c = read();
                Poi_G(1, N - 10, Root[c], y, x);
            } else {
                int x = read(), y_1 = read(), y_2 = read(), Out_Ans(0);
                if(y_1 > y_2) std:: swap(y_1, y_2);
                for(int i = 0; i <= 50; i ++) {
                    Ans = Minx[N - 9];
                    Sec_A(1, N - 10, Root[i], y_1, y_2, x);
                    if(Ans <= x) Out_Ans ++;
                }
                printf("%d
    ", Out_Ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    BackgroundWorker原理剖析
    委托异步调用时BeginInvoke的陷阱处理
    线程静态在对象缓存中的妙用
    值得珍藏的.NET源码,不保存就没机会了
    .NET 4.5.1 参考源码索引
    .NET 4.5 参考源码索引
    .NET 4.0 参考源码索引
    WWF3.5SP1 参考源码索引
    WCF3.5 SP1 参考源码索引
    .NET 3.5.1 参考源码索引
  • 原文地址:https://www.cnblogs.com/shandongs1/p/9526277.html
Copyright © 2011-2022 走看看