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;
    }
  • 相关阅读:
    UVa 116 单向TSP(多段图最短路)
    POJ 1328 Radar Installation(贪心)
    POJ 1260 Pearls
    POJ 1836 Alignment
    POJ 3267 The Cow Lexicon
    UVa 1620 懒惰的苏珊(逆序数)
    POJ 1018 Communication System(DP)
    UVa 1347 旅行
    UVa 437 巴比伦塔
    UVa 1025 城市里的间谍
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9135972.html
Copyright © 2011-2022 走看看