zoukankan      html  css  js  c++  java
  • bzoj 3720: Gty的妹子树

    3720: Gty的妹子树

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

    Time Limit: 10 Sec  Memory Limit: 128 MB

    Description

    我曾在弦歌之中听过你,

    檀板声碎,半出折子戏。

    舞榭歌台被风吹去,

    岁月深处尚有余音一缕……


    Gty神(xian)犇(chong)从来不缺妹子……

    他来到了一棵妹子树下,发现每个妹子有一个美丽度……

    由于Gty很哲♂学,他只对美丽度大于某个值的妹子感兴趣。

    他想知道某个子树中美丽度大于k的妹子个数。

    某个妹子的美丽度可能发生变化……

    树上可能会出现一只新的妹子……


    维护一棵初始有n个节点的有根树(根节点为1),树上节点编号为1-n,每个点有一个权值wi。

    支持以下操作:

    0 u x          询问以u为根的子树中,严格大于x的值的个数。(u^=lastans,x^=lastans)

    1 u x          把u节点的权值改成x。(u^=lastans,x^=lastans)

    2 u x          添加一个编号为"当前树中节点数+1"的节点,其父节点为u,其权值为x。(u^=lastans,x^=lastans)

    最开始时lastans=0。

    Input

    输入第一行包括一个正整数n(1<=n<=30000),代表树上的初始节点数。

    接下来n-1行,每行2个整数u,v,为树上的一条无向边。

    任何时刻,树上的任何权值大于等于0,且两两不同。

    接下来1行,包括n个整数wi,表示初始时每个节点的权值。

    接下来1行,包括1个整数m(1<=m<=30000),表示操作总数。

    接下来m行,每行包括三个整数 op,u,v:

    op,u,v的含义见题目描述。

    保证题目涉及的所有数在int内。

    Output

    对每个op=0,输出一行,包括一个整数,意义见题目描述。

    Sample Input

    2
    1 2
    10 20
    1
    0 1 5

    Sample Output

    2
    树上分块,块与块之间是树的关系
    首先将树以根号n为标准分为根号n块,怎么分呢?
    对于每个节点,维护
    siz[],以其为根的子树的大小
    bl[],它属于哪一块
    开始所有的siz[i]=1,bl[i]=i
    然后在dfs过程中合并这n块,
    当到i的子节点时,若父节点siz[]<根号n时,点i与他的父节点合并为一块
    父节点siz[]=根号n,点i另成一块,并与父节点所在块之间连一条边
    查询操作:
    属于一整块的二分,不属于一块的枚举
    什么意思呢?
    每一块肯定都有一个根节点,即bl[i]=i的点
    所以若bl[x]=x,那就二分x所在块,否则就枚举x的每个儿子
    修改操作:
    二分找到块内位置,直接修改,然后排序
    添加操作:
    如果父节点所在块大小<S,加到父节点所在块内
    否则,自己另成一块,并与父节点所在块连一条边
    小细节:
    块与块之间连边的时候,由父节点所在块向子节点所在块连单向边,
    这样在查询的时候,查询同一整块保证了从x一直往下查
    或者连双向边,对于每个点记录deep[]表示点的深度
    查询的时候,若下一个块的根节点的deep<当前块的根节点的deep,就跳过
    #include<cstdio>
    #include<cmath>
    #include<vector> 
    #include<algorithm>
    #define N 30001
    using namespace std;
    int n,m,tot,S,last,ans;
    int front[N*2],nextt[N*4],to[N*4],Fa[N*2];
    int w[N*2];
    int siz[N*2],bl[N*2];
    vector<int>g[N*2];
    vector<int>block[N*2];
    void add(int u,int v)
    {
        to[++tot]=v;nextt[tot]=front[u];front[u]=tot;
        to[++tot]=u;nextt[tot]=front[v];front[v]=tot;
    }
    void dfs(int x)
    {
        for(int i=front[x];i;i=nextt[i])
        {
            if(to[i]==Fa[x]) continue;
            Fa[to[i]]=x;
            if(siz[x]<S) 
            {
                siz[bl[to[i]]=bl[x]]++;
                block[bl[x]].push_back(w[to[i]]);
            }
            else    g[bl[x]].push_back(bl[to[i]]);
            dfs(to[i]);
        }
    }
    void query(int x,int y)
    {
        if(bl[x]==x)
        {
            ans+=block[x].end()-upper_bound(block[x].begin(),block[x].end(),y);
            for(int i=0;i<g[bl[x]].size();i++)
            {
                int v=g[bl[x]][i];
                query(v,y);
            }
        }
        else
        {
            ans+=w[x]>y; 
            for(int i=front[x];i;i=nextt[i])
            {
                if(to[i]==Fa[x]) continue;
                query(to[i],y);
            }
        }
    }
    
    void change(int x,int y)
    {
        int pos=lower_bound(block[bl[x]].begin(),block[bl[x]].end(),w[x])-block[bl[x]].begin();
        block[bl[x]][pos]=y;w[x]=y;
        sort(block[bl[x]].begin(),block[bl[x]].end());
    }
    void insert(int u,int val)
    {
        Fa[++n]=u;add(u,n);w[n]=val;
        if(siz[bl[u]]<S)
        {
            bl[n]=bl[u];block[bl[n]].push_back(val);
            sort(block[bl[n]].begin(),block[bl[n]].end());
        }
        else
        {
            bl[n]=n;block[bl[n]].push_back(val);
            g[bl[u]].push_back(bl[n]);
        }
    }
    int main()
    {
        scanf("%d",&n);
        int x,y,z;S=sqrt(n);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        for(int i=1;i<=n;i++) scanf("%d",&w[i]),bl[i]=i,siz[i]=1;
        dfs(1);
        for(int i=1;i<=n;i++) 
         if(bl[i]==i) block[i].push_back(w[i]),sort(block[i].begin(),block[i].end());
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&z,&x,&y);
            x^=last;y^=last;
            if(!z)
            {
                query(x,y);
                printf("%d
    ",ans);
                last=ans;
                ans=0;
            }
            else if(z==1)  change(x,y);
            else insert(x,y);
        }
    }
  • 相关阅读:
    golang的缓冲channel简单使用
    golang协程同步的几种方法
    红黑树原理详解及golang实现
    go路由httprouter中的压缩字典树算法图解及c++实现
    golang编译源代码和交叉编译方法
    cmake使用笔记
    如何用redis设计数据库初探
    muduo学习笔记(六) 多线程的TcpServer
    利用 Blob 处理 node 层返回的二进制文件流字符串并下载文件
    数据量庞大的分页穿梭框实现
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6560137.html
Copyright © 2011-2022 走看看