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\n",ans);
            last=ans;
            ans=0;
        }
        else if(z==1)  change(x,y);
        else insert(x,y);
    }
}

 

posted @ 2017-03-16 16:23  TRTTG  阅读(381)  评论(0编辑  收藏  举报