HDU 6183 Color it 动态开点线段树

题意:

有四种操作。 
0:清除所有点 
1 x y c:给点(x,y)添加一种颜色c 
2 x y1 y2:在(0,y1)与(x,y2)所围成的矩形里有多少种颜色 
3:程序结束

分析:

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

/*
建立50颗线段树
没颗线段树表示y轴区间所能取到的x坐标的最小值。
*/
#include<bits/stdc++.h>

using namespace std;

int tree[55];

const int maxn=1e6+10;

int tot;
int l[maxn],r[maxn],v[maxn];

void change(int &k,int L,int R,int y,int x){
    if(!k){
        k=++tot;
        v[k]=x;
    }
    v[k]=min(v[k],x);
    if(L==R) return ;
    int mid=L+R>>1;
    if(y<=mid) change(l[k],L,mid,y,x);
    else change(r[k],mid+1,R,y,x);
}

void query(int k,int L,int R,int tl,int tr,int x,bool& flag){
    if(flag||!k) return ;
    if(tl>R||tr<L) return;
    if(tl<=L&&R<=tr){
        if(v[k]<=x) flag=1;
        return;
    }
    int mid=L+R>>1;
    query(l[k],L,mid,tl,tr,x,flag);
    query(r[k],mid+1,R,tl,tr,x,flag);
}

int main(){
    int op;
    while(scanf("%d",&op)!=EOF){
        if(op==3) break;
        if(op==0){
            memset(tree,0,sizeof tree);
            for(int i=1;i<=tot;i++) l[i]=r[i]=0;
            tot=0;
        }else if(op==1){
            int x,y,c;
            scanf("%d%d%d",&x,&y,&c);
            change(tree[c],1,1e6,y,x);
        }else{
            int x,y1,y2,ans=0;
            scanf("%d%d%d",&x,&y1,&y2);
            for(int i=0;i<=50;i++){
                bool flag=0;
                query(tree[i],1,1e6,y1,y2,x,flag);
                if(flag) ans++;
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40679299/article/details/83653641