HDU6183(动态开点线段树)

题目链接

题目大意:

有四种操作。
0

:清除所有点
1 x y c:给点 (x,y)添加一种颜色 c
2 x y1 y2:在 (0,y1)(x,y2)所围成的矩形里有多少种颜色
3

:程序结束

笔记

注意这里一个点可以有很多种颜色,是不会被覆盖的。
颜色最多51种。我们就建51棵线段树。
每个线段树按y

轴建树,每个结点的值是在范围内的最小的 x
ps:看了cls(claris)的cpp感觉学到了姿势啊。orz.

时间复杂度O(50nlogn)

#include <bits/stdc++.h>

using namespace std;
const int maxn = 2e6 + 7, up = 1e6;
struct node
{
    int lc, rc, v;
    node() {lc=rc=v=0;}
}t[maxn<<1];
int rt[51], fg, tot;
void update(int &c, int l, int r, int pos, int v)
{
    if(!c) {
        c = ++tot;
        t[c].v = v;
    }
    t[c].v = min(t[c].v, v);
    if(l == r) return;
    int mid = (l + r) / 2;
    if(pos <= mid) update(t[c].lc, l, mid, pos, v);
    else update(t[c].rc, mid+1, r, pos, v);
}
void query(int c, int x, int L, int R, int l, int r)
{
    if(fg || !c) return;
    if(L <= l && r <= R) {
        if(t[c].v <= x) fg = 1;
        return ;
    }
    int mid = (l + r) / 2;
    if(L <= mid) query(t[c].lc, x, L, R, l, mid);
    if(R > mid) query(t[c].rc, x, L, R, mid+1, r);
}
int main()
{
    //freopen("f:\\out.txt","w",stdout);
    int opt;
    while(scanf("%d", &opt)) {
        if(opt == 3) break;
        if(opt == 0) {
            for(int i = 1;i <= tot;i ++) t[i].lc = t[i].rc = t[i].v = 0;
            for(int i = 0;i <= 50;i ++) rt[i] = 0;
            tot = 0;
        } else if(opt == 1) {
            int x, y, c;
            scanf("%d %d %d", &x, &y, &c);
            update(rt[c], 1, up, y, x);
        } else {
            int res = 0;
            int x, y1, y2;
            scanf("%d %d %d", &x, &y1, &y2);
            for(int i = 0;i <= 50;i ++) {
                fg = 0;
                query(rt[i], x, y1, y2, 1, up);
                if(fg) res ++;
            }
            printf("%d\n", res);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36876305/article/details/80466555