luoguP2137 Gty的妹子树 分块+主席树+DFS序

对于一类带修改问题可以采用对时间(操作)分块,然后定期重构的方式来维护.   

设块的大小为 $B$,则重构 $\frac{Q}{B}$ 次,每次查询的复杂度为 $O(B \log n)$.     

计算一下 $B$ 的大小来平衡重构和查询的复杂度即可.   

这种纯数据结构题都挺好写的.  

code: 

#include    
#include       
#include  
#include     
#define N 60009   
#define ll long long 
#define INF 1000000  
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;   
const int B=600;                     
int n,edges,tim,tot,cn,cnt; 
vectorG;   
int dfn[N<<1],bu[N<<1],ed[N<<1],rt[N<<1],A[N<<1],IN[N<<1];        
int hd[N<<1],to[N<<2],nex[N<<2],fa[19][N<<1],val[N<<1],dep[N<<1];           
struct data { 
    int ls,rs,sum;     
    data() { ls=rs=sum=0; }  
}s[N*50];  
void add(int u,int v) {  
    nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;  
}    
void dfs(int x,int ff) {   
    fa[0][x]=ff;
    dep[x]=dep[ff]+1;     
    dfn[x]=++tim,bu[tim]=x;  
    for(int i=hd[x];i;i=nex[i])
        if(to[i]!=ff) dfs(to[i],x);   
    ed[x]=tim;   
}        
int update(int pre,int l,int r,int p,int v) {  
    int now=++tot;   
    s[now]=s[pre];    
    s[now].sum+=v;  
    if(l==r) return now;   
    int mid=(l+r)>>1;  
    if(p<=mid)  s[now].ls=update(s[pre].ls,l,mid,p,v);   
    else s[now].rs=update(s[pre].rs,mid+1,r,p,v);   
    return now;    
}
int query(int x,int l,int r,int L,int R) {  
    if(!x) return 0;  
    if(l>=L&&r<=R) return s[x].sum;  
    int mid=(l+r)>>1,re=0; 
    if(L<=mid)  re+=query(s[x].ls,l,mid,L,R);  
    if(R>mid)   re+=query(s[x].rs,mid+1,r,L,R);  
    return re;   
}
void CON() {                
    for(int i=1;i<=tot;++i) s[i]=data();      
    tot=0,rt[0]=0,tim=0,cnt=0; 
    dfs(1,0);   
    int x,y,z;   
    for(int i=1;i<=n;++i)   A[++cnt]=val[i];   
    sort(A+1,A+1+cnt);                                      
    for(int i=1;i<=n;++i) {    
        z=lower_bound(A+1,A+1+cnt,val[bu[i]])-A;         
        rt[i]=update(rt[i-1],1,INF,z,1);   
    }     
    for(int i=0;idep[y]) swap(x,y);   
        for(int i=18;i>=0;--i) if(dep[fa[i][y]]>=dep[x]) y=fa[i][y];    
    }  
    if(x==y) return x;     
    for(int i=18;i>=0;--i) {  
        if(fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y];  
    }  
    return fa[0][x];    
}
int main() {
    // setIO("input");                  
    int x,y,z,m;   
    scanf("%d",&n);  
    for(int i=1;iA[cnt]) y=INF;  
            else y=lower_bound(A+1,A+1+cnt,y+1)-A;                                         
            int ans=query(rt[ed[x]],1,INF,y,INF)-query(rt[dfn[x]-1],1,INF,y,INF);  
            for(int j=0;j=dfn[x]&&dfn[p]<=ed[x]) {             
                    int ori=query(rt[dfn[p]],1,INF,y,INF)-query(rt[dfn[p]-1],1,INF,y,INF); 
                    if(ori&&val[p]<=tmp) --ans;   
                    if(!ori&&val[p]>tmp) ++ans;              
                }
            }                          
            for(int j=POS+1;j<=n;++j) if(get_lca(j,x)==x&&val[j]>tmp) ++ans; 
            printf("%d\n",lastans=ans);       
        } 
        if(z==1) {                
            ++cn,val[x]=y;     
            if(x<=POS&&!IN[x]) G.push_back(x),IN[x]=1;       
        } 
        if(z==2) {     
            ++cn,++n;   
            val[n]=y,fa[0][n]=x,add(fa[0][n],n),dep[n]=dep[x]+1;       
            for(int j=1;j<19;++j) fa[j][n]=fa[j-1][fa[j-1][n]];     
            if(cn>B) CON(),POS=n,cn=0;   
        }
    }
    return 0; 
}

  

你可能感兴趣的:(luoguP2137 Gty的妹子树 分块+主席树+DFS序)