BZOJ3196 二逼平衡樹(線段樹套線段樹)

題目大意

一種數據結構,維護一個有序數列,其中需要提供以下操作:
1.查詢k在區間內的排名
2.查詢區間內排名爲k的值
3.修改某一位值上的數值
4.查詢k在區間內的前驅(前驅定義爲小於x,且最大的數)
5.查詢k在區間內的後繼(後繼定義爲大於x,且最小的數)

Solution

查詢k在的排名,k的前驅,後繼,能馬上想到用平衡樹維護。而因爲是在區間中詢問的,所以要用到樹套樹。外層維護一棵線段樹,內層平衡樹,就能查詢區間了。複雜度(logn)2
而操作2,好像只能二分答案,再進行操作1,複雜度達到了令人絕望的(logn)3 ……
其實我們可以將內層的平衡樹替換爲一棵權值線段樹。同樣可以實現操作1和操作3,操作2時把這個區間包含的權值線段樹都拿出來,再一起二分,複雜度就變成了(logn)2 。操作4和5有點麻煩,但是前驅可以通過操作1和2得到,後繼也同理。我們就能維護所有操作了。總時間複雜度nlogn2

考慮到一個問題,維護權值線段樹內存是nlogn ,整顆樹的內存就變成了nlogn2 ,而BZOJ上內存只給了128MB,只能開3個10000000的數組,根本過不了TT。
於是只好硬生生把原來在線的問題變成了離線。先進行離散化,把權值線段樹值域縮小,纔剛好夠了空間。空間是不是很絕望?

/**************************************************************
    Problem: 3196
    Language: C++
    Result: Accepted
    Time:4916 ms
    Memory:120984 kb
****************************************************************/

#include<cstdio>
#include<algorithm>
using namespace std;
int cnt,lson[10000010],rson[10000010],tree[10000010];
int root[200010],a[50010],q[10010];
int Small,Max,ta,b[100010],O[50010],l[50010],r[50010],k[50010],val[200010];
void insert(int &u,int l,int r,int key)
{
    if (!u) u=++cnt;
    if (l==r)
    {
        tree[u]++;
        return;
    }
    int mid=(l+r)>>1;
    if (key<=mid) insert(lson[u],l,mid,key);
    else insert(rson[u],mid+1,r,key);
    tree[u]=tree[lson[u]]+tree[rson[u]];
}
void build(int l,int r,int t)
{
    for (int i=l;i<=r;i++)
        insert(root[t],0,100000,a[i]);
    if (l==r)
    { 
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,t<<1);
    build(mid+1,r,t<<1|1);    
}
void query_small(int t,int l,int r,int x,int y)
{
    if (!t) return;
    if (l==x&&y==r)
    {
        Small+=tree[t];
        return;
    }
    int mid=(l+r)>>1;
    if (y<=mid) query_small(lson[t],l,mid,x,y);
    else if (x>mid) query_small(rson[t],mid+1,r,x,y);
    else query_small(lson[t],l,mid,x,mid),query_small(rson[t],mid+1,r,mid+1,y);
}
void query_randmin(int l,int r,int x,int y,int t,int key)
{
    if (l==x&&y==r)
    {
        query_small(root[t],0,100000,0,key-1);
        return;
    }
    int mid=(l+r)>>1;
    if (y<=mid) query_randmin(l,mid,x,y,t<<1,key);
    else if (x>mid) query_randmin(mid+1,r,x,y,t<<1|1,key);
    else query_randmin(l,mid,x,mid,t<<1,key),query_randmin(mid+1,r,mid+1,y,t<<1|1,key); 
}
void query_queue(int l,int r,int x,int y,int t)
{
    if (l==x&&y==r)
    {
        q[++ta]=root[t];
        return;
    }
    int mid=(l+r)>>1;
    if (y<=mid) query_queue(l,mid,x,y,t<<1);
    else if (x>mid) query_queue(mid+1,r,x,y,t<<1|1);
    else query_queue(l,mid,x,mid,t<<1),query_queue(mid+1,r,mid+1,y,t<<1|1); 
}
int query_rand(int l,int r,int k)
{
    if (l==r) return l;
    int mid=(l+r)>>1;
    int sum=0;
    for (int i=1;i<=ta;i++)
        sum+=tree[lson[q[i]]];
    if (k<=sum) 
    {
        for (int i=1;i<=ta;i++) q[i]=lson[q[i]];
        return query_rand(l,mid,k);
    }
    else
    {
        for (int i=1;i<=ta;i++) q[i]=rson[q[i]];
        return query_rand(mid+1,r,k-sum);
    }
}
void query_max(int t,int l,int r,int x,int y)
{
    if (!t) return;
    if (l==x&&y==r)
    {
        Max+=tree[t];
        return;
    }
    int mid=(l+r)>>1;
    if (y<=mid) query_max(lson[t],l,mid,x,y);
    else if (x>mid) query_max(rson[t],mid+1,r,x,y);
    else query_max(lson[t],l,mid,x,mid),query_max(rson[t],mid+1,r,mid+1,y);
}
void query_randmax(int l,int r,int x,int y,int t,int key)
{
    if (l==x&&y==r)
    {
        query_max(root[t],0,100000,key+1,100000);
        return;
    }
    int mid=(l+r)>>1;
    if (y<=mid) query_randmax(l,mid,x,y,t<<1,key);
    else if (x>mid) query_randmax(mid+1,r,x,y,t<<1|1,key);
    else query_randmax(l,mid,x,mid,t<<1,key),query_randmax(mid+1,r,mid+1,y,t<<1|1,key); 
}
int query_rands(int l,int r,int k)
{
    if (l==r) return l;
    int mid=(l+r)>>1;
    int sum=0;
    for (int i=1;i<=ta;i++)
        sum+=tree[rson[q[i]]];
    if (k<=sum) 
    {
        for (int i=1;i<=ta;i++)
            q[i]=rson[q[i]];
        return query_rands(mid+1,r,k);
    }
    else
    {
        for (int i=1;i<=ta;i++)
            q[i]=lson[q[i]];
        return query_rands(l,mid,k-sum);
    }
}
void ins(int &t,int l,int r,int key,int Add)
{
    if (!t) t=++cnt;
    if (l==r)
    {
        tree[t]+=Add;
        return;
    }
    int mid=(l+r)>>1;
    if (key<=mid) ins(lson[t],l,mid,key,Add);
    else ins(rson[t],mid+1,r,key,Add);
    tree[t]=tree[lson[t]]+tree[rson[t]];
}
void modify(int l,int r,int t,int pos,int key,int Add)
{
    if (l==r)
    {
        ins(root[t],0,100000,key,Add);
        return;
    }
    int mid=(l+r)>>1;
    if (pos<=mid) modify(l,mid,t<<1,pos,key,Add);
    else modify(mid+1,r,t<<1|1,pos,key,Add);
    ins(root[t],0,100000,key,Add);
}
int main()
{
    //freopen("data10.in","r",stdin);
    //freopen("data10.out","w",stdout); 
    int n,m,cc=0;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[++cc]=a[i];
    }
    for (int i=1;i<=m;i++)
    {
        scanf("%d",&O[i]);
        if (O[i]==1) scanf("%d%d%d",&l[i],&r[i],&k[i]),b[++cc]=k[i];
        if (O[i]==2) scanf("%d%d%d",&l[i],&r[i],&k[i]);
        if (O[i]==3) scanf("%d%d",&l[i],&k[i]),b[++cc]=k[i];
        if (O[i]==4) scanf("%d%d%d",&l[i],&r[i],&k[i]),b[++cc]=k[i];
        if (O[i]==5) scanf("%d%d%d",&l[i],&r[i],&k[i]),b[++cc]=k[i];
    }
    sort(b+1,b+1+cc);
    int n1=unique(b+1,b+1+cc)-b-1;
    for (int i=1;i<=n;i++)
    {
        int xx=lower_bound(b+1,b+1+n1,a[i])-b;
        val[xx]=a[i],a[i]=xx;
    } 
    for (int i=1;i<=m;i++)
        if (O[i]!=2) 
        {
            int xx=lower_bound(b+1,b+1+n1,k[i])-b;
            val[xx]=k[i],k[i]=xx;
        }
    build(1,n,1);
    for (int i=1;i<=m;i++)
    {
        if (O[i]==1)
        {
            Small=0;
            query_randmin(1,n,l[i],r[i],1,k[i]);
            printf("%d\n",Small+1);
        }
        if (O[i]==2)
        {
            ta=0;
            query_queue(1,n,l[i],r[i],1);
            printf("%d\n",val[query_rand(0,100000,k[i])]);
        }
        if (O[i]==3)
        {
            //if (a[l[i]]==k[i]) continue;
            modify(1,n,1,l[i],a[l[i]],-1);
            modify(1,n,1,l[i],k[i],1);
            a[l[i]]=k[i];
        }
        if (O[i]==4)
        {
            Small=0;
            query_randmin(1,n,l[i],r[i],1,k[i]);
            ta=0;
            query_queue(1,n,l[i],r[i],1);
            printf("%d\n",val[query_rand(0,100000,Small)]);
        }
        if (O[i]==5)
        {
            Max=0;
            query_randmax(1,n,l[i],r[i],1,k[i]);
            ta=0;
            query_queue(1,n,l[i],r[i],1);
            printf("%d\n",val[query_rands(0,100000,Max)]);
        }
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章