1. 程式人生 > >hdu 6183 線段樹的空間優化

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\n",ret);
        }
        else if(op==3) break;
    }
}