hdu 6183 线段树的空间优化

题意:

一个空的坐标系,有④种操作:①1 x y c表示在(x, y)点染上颜色c;②2 X y1 y2表示查询在(1, y1)到(X, y2)范围内有多少种不同的颜色:

③0表示清屏;④3表示程序退出(0<=x, y<=1000000, 0<=c<=50)

 

思路:开五十个线段树(一种颜色一个),以y为下表,保存min x,(因为查询x固定1---X)然后暴力查询50个就好了

但是显然碰到了一个问题,1e6 开50个线段树显然不现实。。所以需要空间优化一下。。。这里我们考虑动态来开辟线段树,有效的节点进行分配,无效则不分配。。。提问,这样空间为什么是合理的呢?其实因为一个add 最多开logn个节点,单组只有1.5e5次查询,显然,最多也就只开了qlogn个。那么这样空间复杂度就是合理的了。。具体动态开辟的实现也非常简单,类比trie,见代码。

 

代码:

 

#include<bits/stdc++.h>
using namespace std;
#define MEM(x,y) memset(x,y,sizeof(x));
const int maxn=3e6+10;
int root[55];
int L[maxn],R[maxn],tot,sum[maxn];
void update(int &rt,int idx,int val,int l,int r){
    if(rt==-1) rt=tot++;
    sum[rt]=min(val,sum[rt]);
    if(l==r) return;
    int mid=(l+r)/2;
    if(idx<=mid) update(L[rt],idx,val,l,mid);
    else update(R[rt],idx,val,mid+1,r);
    return;
}
int query(int rt,int l,int r,int ll,int rr){
    int ret=1e9;
    if(rt==-1) return ret;
    if(ll==l&&rr==r) return sum[rt];
    int mid=(ll+rr)/2;
    if(r<=mid) ret=query(L[rt],l,r,ll,mid);
    else if(l>mid) ret=query(R[rt],l,r,mid+1,rr);
    else ret=min(query(L[rt],l,mid,ll,mid),query(R[rt],mid+1,r,mid+1,rr));
    return ret;
}
int main(){
    int t,n,op,x,y,y1,y2,c,ret;
    while(scanf("%d",&op)){
        if(op==0){
            MEM(L,-1);MEM(R,-1);
            for(int i=0;i<maxn;++i) sum[i]=1e9;
            tot=52;
        }
        else if(op==1){
            scanf("%d%d%d",&x,&y,&c);
            update(c,y,x,1,1e6);
        }
        else if(op==2){
            scanf("%d%d%d",&x,&y1,&y2);
            ret=0;
            for(int i=0;i<=50;++i)
                ret+=(query(i,y1,y2,1,1e6)<=x);
            printf("%d
",ret);
        }
        else if(op==3) break;
    }
}




原文地址:https://www.cnblogs.com/zhangxianlong/p/10672487.html