zoukankan      html  css  js  c++  java
  • [bzoj3720]Gty的妹子树【树分块】

    【题目链接】
      http://www.lydsy.com/JudgeOnline/problem.php?id=3720
    【题解】
      按dfs序树分块的模板题。
      每个节点的子树在dfs序中一定为一串连续的区间,那我们对dfs序分块就行了,每个块内元素按大小排序。查询时暴力找边界上的块,中间的块二分一下。修改时暴力维护大小顺序,插入时插在它的父亲后(dfs序为它的父亲+1),然后暴力修改当前块的dfs序。
      复杂度O(nnlogn) 可以修改块的大小使复杂度更优。
      

    /* --------------
        user Vanisher
        problem bzoj-3720 
    ----------------*/
    # include <bits/stdc++.h>
    # define    ll      long long
    # define    inf     0x3f3f3f3f
    # define    N       60010
    # define    K       1001
    using namespace std;
    int read(){
        int tmp=0, fh=1; char ch=getchar();
        while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
        while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
        return tmp*fh;
    }
    
    struct Edge{
        int data,next;
    }e[N*2];
    struct node{
        int id,p;
    }k[K][K];
    int w[N],nex[K],n,T,now,kdep[K],num,size[K],dep[N],nowdep,p[N],dad[N],head[N],place;
    bool cmpw(node x, node y){
        return w[x.id]<w[y.id];
    }
    bool cmpp(node x, node y){
        return x.p<y.p;
    }
    void build(int u, int v){
        e[++place].data=v; e[place].next=head[u]; head[u]=place;
        e[++place].data=u; e[place].next=head[v]; head[v]=place;
    }
    void dfs(int x, int fa){
        if (now==T){
            nex[num]=num+1;
            size[num]=now;
            sort(k[num]+1,k[num]+size[num]+1,cmpw);
            kdep[num]=nowdep;
            now=0; nowdep=inf; num++;
        }
        k[num][++now]={x,now}; p[x]=num; dad[x]=fa;
        dep[x]=dep[fa]+1, nowdep=min(dep[x],nowdep);
        for (int ed=head[x]; ed!=0; ed=e[ed].next)
            if (e[ed].data!=fa)
                dfs(e[ed].data,x);
    }
    int query(int x, int y){
        int ans=0, l, r=size[p[x]], ed;
    
        for (int i=1; i<=size[p[x]]; i++)
            if (k[p[x]][i].id==x) l=k[p[x]][i].p;
        for (int i=1; i<=size[p[x]]; i++)
            if (dep[k[p[x]][i].id]<=dep[x]&&k[p[x]][i].p>l)
                r=min(k[p[x]][i].p-1,r);
        for (int i=1; i<=size[p[x]]; i++)
            if (k[p[x]][i].p>=l&&k[p[x]][i].p<=r)
                if (w[k[p[x]][i].id]>y) ans++;
    
        if (r!=size[p[x]]) return ans;
        for (ed=nex[p[x]]; kdep[ed]>dep[x]; ed=nex[ed]){
            int pl=1, pr=size[ed], now=pr+1;
            while(pl<=pr){
                int mid=(pl+pr)/2;
                if (w[k[ed][mid].id]>y)
                    now=mid, pr=mid-1;
                    else pl=mid+1;
            }
            ans=ans+size[ed]+1-now;
        } 
    
        l=1, r=size[ed];
        for (int i=1; i<=size[ed]; i++)
            if (dep[k[ed][i].id]<=dep[x])
                r=min(r,k[ed][i].p-1);
        for (int i=1; i<=size[ed]; i++)
            if (k[ed][i].p>=l&&k[ed][i].p<=r)
                if (w[k[ed][i].id]>y) ans++;
        return ans;
    }
    void modify(int x, int y){
        w[x]=y;
        for (int i=1; i<=size[p[x]]; i++)
            if (k[p[x]][i].id==x){
                for (int j=i+1; j<=size[p[x]]&&w[k[p[x]][j].id]<w[k[p[x]][j-1].id]; j++)
                    swap(k[p[x]][j],k[p[x]][j-1]);
                for (int j=i-1; j>0&&w[k[p[x]][j].id]>w[k[p[x]][j+1].id]; j--)
                    swap(k[p[x]][j],k[p[x]][j+1]);
                return; 
            }
    } 
    void cut(int x){
        int now=size[x]/2;
        sort(k[x]+1,k[x]+size[x]+1,cmpp);
        size[++num]=now; size[x]=now;
        nex[num]=nex[x]; nex[x]=num;
        kdep[x]=inf, kdep[num]=inf;
        for (int i=1; i<=now; i++){
            k[num][i]=k[x][i+now];
            k[num][i].p-=now;
            kdep[x]=min(kdep[x],dep[k[x][i].id]);
            kdep[num]=min(kdep[num],dep[k[num][i].id]);
            p[k[num][i].id]=num;
        }
        sort(k[x]+1,k[x]+size[x]+1,cmpw);
        sort(k[num]+1,k[num]+size[num]+1,cmpw);
    }
    void extend(int x, int y){
        w[++n]=y; T=(int)sqrt(n)+1; dep[n]=dep[x]+1;
        for (int i=1; i<=size[p[x]]; i++)
            if (k[p[x]][i].id==x){
                for (int j=1; j<=size[p[x]]; j++)
                    if (k[p[x]][j].p>k[p[x]][i].p)
                        k[p[x]][j].p++;
                k[p[x]][++size[p[x]]]={n,k[p[x]][i].p+1}; p[n]=p[x];
                for (int j=size[p[x]]-1; j>0&&w[k[p[x]][j].id]>w[k[p[x]][j+1].id]; j--)
                    swap(k[p[x]][j],k[p[x]][j+1]);
                if (size[p[x]]>=2*T) cut(p[x]);
                return;
            }
    }
    int main(){
        n=read(); T=(int)sqrt(n)+1;
        for (int i=1; i<n; i++)
            build(read(),read());
        for (int i=1; i<=n; i++)
            w[i]=read();
        num=1; now=0; nowdep=inf;
        dfs(1,0); 
        size[num]=now; kdep[num]=nowdep; 
        sort(k[num]+1,k[num]+size[num]+1,cmpw);
        int m=read(), lastans=0;
        for (int i=1; i<=m; i++){
            int opt=read(),x=read(),w=read();
            x=x^lastans, w=w^lastans;
            if (opt==0){
                lastans=query(x,w);
                printf("%d
    ",lastans);
            }
            if (opt==1) modify(x,w);
            if (opt==2) extend(x,w);
        }
        return 0;
    }
  • 相关阅读:
    B-tree/B+tree/B*tree
    java拆装箱(转)
    C语言身份证信息查询系统(修改版)
    UC编程:字符读取与行读取
    UC编程:通过fwrite()和write()比较标准库函数和系统调用的速度
    UC编程:输入输出重定向(系统调用)
    UC编程:输入输出重定向(标准IO)
    UC编程:环境变量的查询与修改
    Perl基础(1)chop与chomp的区别
    假期“实习”20天生存实录
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9135972.html
Copyright © 2011-2022 走看看