hdu 6183 Color it线段树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yqdjl6/article/details/82933932

两种操作,第一种操作给点(x,y)添加一种颜色c (x,y<=1e6,c<=50);第二种操作在(1,y1)与(x,y2)所围成的矩形里有多少种颜色。操作数<15e5

这道题刚开始自己用set都能肝过去…感觉数据有点水
这道题正解应该是用51个Y轴建线段树,记录[y1,y2]的标记为i(i从0到50)的最小值是否小于等于x,开50个线段树有点大,从claris那学了一个厉害的东西

#include<bits/stdc++.h>
using namespace std;
using LL = int64_t;
const LL mod=1e9+7;
const int maxn=15e5+5;
int T[100],l[maxn],r[maxn],v[maxn],tot=0,flag=0;
int x,y1,y2;
void update(int &num,int tl,int tr,int y,int x) {
    if(num==0) {
        num=++tot;
        v[num]=x;
    }
    v[num]=min(v[num],x);
    if(tl==tr) return ;
    int mid=(tl+tr)/2;
    if(y<=mid) update(l[num],tl,mid,y,x);
    else update(r[num],mid+1,tr,y,x);
}

void query(int num,int tl,int tr) {
    if(flag||num==0) return ;
    if(tl>=y1&&tr<=y2) {
        if(v[num]<=x) flag=1;
        return ;
    }
    int mid=(tl+tr)/2;
    if(y1<=mid) query(l[num],tl,mid);
    if(y2>mid) query(r[num],mid+1,tr);
}

int main()
{
    int n;
    while(scanf("%d",&n)) {
        if(n==3) return 0;
        else if(n==0) {
            for(int i=0;i<=50;i++) T[i]=0;
            for(int i=0;i<=tot;i++) l[i]=r[i]=0;
            tot=0;
        }
        else if(n==1) {
            int x,y,z;scanf("%d%d%d",&x,&y,&z);
            update(T[z],1,1000000,y,x);
        }
        else {
            int num=0;scanf("%d%d%d",&x,&y1,&y2);
            for(int i=0;i<=50;i++) {
                query(T[i],1,1000000);
                if(flag) num++,flag=0;
            }
            printf("%d\n",num);
        }
    }
    return 0;
}

其中T[i]代表标记为i的值的头节点是什么,l[i]表示第i个节点的下一个左边节点是什么,r[i]表示第i个节点的下一个右边节点是什么,v[i]表示第i个节点最小值是什么。有种主席树的感觉,感觉很神奇

猜你喜欢

转载自blog.csdn.net/yqdjl6/article/details/82933932