码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 3065 带插入区间K小值

时间:2016-07-21 22:01:20      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:

http://www.lydsy.com/JudgeOnline/problem.php?id=3065

思路:替罪羊树套权值线段树。

当替罪羊树某个子树大于某个比利(比例)时就暴力重构,本题时间复杂度:O(nlog^3n)

#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<vector>
#define alpha 0.75
#define N 10000005
int read(){
    char ch=getchar();int t=0,f=1;
    while (ch<0||ch>9){if (ch==-) f=-1;ch=getchar();}
    while (0<=ch&&ch<=9){t=t*10+ch-0;ch=getchar();}
    return t*f;
}
int tmp;
int n,m,sz,ans,root;
int v[70005],dfn[70005],rt[70005],ls[70005],rs[70005];
struct seg{int l,r,sum;}a[N];
std::vector<int>p,t,rec;
int newnode(){
    if (!rec.size()) return ++sz;
    else{
        int k=rec.back();rec.pop_back();
        return k;
    }
}
void recliam(int &x){
    if (!x) return;
    rec.push_back(x);
    recliam(a[x].l);recliam(a[x].r);
    a[x].sum=0;x=0;
}
void insert(int &k,int l,int r,int val,int f){
    if (!k) k=newnode();
    if (l==r){a[k].sum+=f;return;}
    int mid=(l+r)>>1;
    if (val<=mid) insert(a[k].l,l,mid,val,f);
    else insert(a[k].r,mid+1,r,val,f);
    a[k].sum=a[a[k].l].sum+a[a[k].r].sum;
    if (!a[k].sum) recliam(k);
}
void build(int &k,int l,int r){
    int mid=(l+r)>>1;
    if (l>r) return;
    if (l==r){
        k=dfn[l];insert(rt[k],0,70000,v[k],1);return;
    }
    k=dfn[mid];
    build(ls[k],l,mid-1);build(rs[k],mid+1,r);
    for (int i=l;i<=r;i++)
     insert(rt[k],0,70000,v[dfn[i]],1);
}
void del(int &x){
    if (!x) return;recliam(rt[x]);
    del(ls[x]);p.push_back(x);del(rs[x]);
    x=0;
}
void rebuild(int &x){
    del(x);int s1=p.size();
    for (int i=1;i<=s1;i++) dfn[i]=p[i-1];
    build(x,1,s1);
    p.clear();
}
int modify(int k,int x,int val){
    insert(rt[k],0,70000,val,1);
    int t,L=a[rt[ls[k]]].sum;
    if (L+1==x){t=v[k];v[k]=val;}
    else if (L>=x) t=modify(ls[k],x,val);
    else t=modify(rs[k],x-L-1,val);
    insert(rt[k],0,70000,t,-1);
    return t;
}
void query(int k,int l,int r){
    int L=a[rt[ls[k]]].sum,R=a[rt[k]].sum;
    if (l==1&&r==R){t.push_back(rt[k]);return;}
    if (l<=L+1&&r>=L+1)p.push_back(v[k]);
    if (r<=L)query(ls[k],l,r);
    else if (l>L+1) query(rs[k],l-L-1,r-L-1);
    else{
        if (l<=L) query(ls[k],l,L);
        if (R>L+1) query(rs[k],1,r-L-1);
    }
}
int solve_query(int L,int R,int K){
    query(root,L,R);K--;
    int l=0,r=70000,s1=t.size(),s2=p.size();
    while (l<r){
        int mid=(l+r)>>1,sum=0;
        for (int i=0;i<s1;i++) sum+=a[a[t[i]].l].sum;
        for (int i=0;i<s2;i++)
         if (p[i]>=l&&p[i]<=mid) sum++;
        if (K<sum){
            for (int i=0;i<s1;i++) t[i]=a[t[i]].l;
            r=mid;
        } else{
            for (int i=0;i<s1;i++) t[i]=a[t[i]].r;
            l=mid+1;K-=sum;
        }
    }
    t.clear();p.clear();
    return l;
}
void insert(int &k,int x,int val){
    if (!k){
        k=++n;
        insert(rt[k],0,70000,val,1);
        v[k]=val;
        return;
    }
    insert(rt[k],0,70000,val,1);
    int L=a[rt[ls[k]]].sum;
    if (L>=x) insert(ls[k],x,val);else insert(rs[k],x-L-1,val);
    if (a[rt[k]].sum*alpha>std::max((double)a[rt[ls[k]]].sum,(double)a[rt[rs[k]]].sum)){
        if (tmp){
            if (ls[k]==tmp) rebuild(ls[k]);
            else rebuild(rs[k]);
            tmp=0; 
        }
    }else tmp=k;    
}
int main(){
    n=read();
    for (int i=1;i<=n;i++) v[i]=read();
    for (int i=1;i<=n;i++) dfn[i]=i;
    build(root,1,n);
    m=read();
    char ch[2];int x,y,K;
    while (m--){
        scanf("%s",ch);
        x=read();y=read();x^=ans;y^=ans;
        switch(ch[0]){
            case Q:K=read();K^=ans;ans=solve_query(x,y,K);printf("%d\n",ans);break;
            case M:modify(root,x,y);break;
            case I:tmp=0;insert(root,x-1,y);if (tmp){tmp=0;rebuild(root);}break;
        }
    }
}

 

BZOJ 3065 带插入区间K小值

标签:

原文地址:http://www.cnblogs.com/qzqzgfy/p/5693207.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!