【bzoj3720】GTY的妹子树【块状树模板】

bzoj3720GTY的妹子树

圆方树上块状果,点分树下你和我,虚树下面做游戏,仙人掌上欢乐多
这道题题目很长
大概说的是:
要求你写出一个数据结构,维护一颗带点权的树,兹瓷:
~~
1. 单点修改点权
2. 查询子树内点权大于x的点的个数
3. 新给出一个点,并将这个点与已有点做link
~~

似乎以前学过的任何数据结构都不能做这么奇怪的事情呢
我们的块状树就闪亮登场啦
我们对一棵树进行分块
然后就可以用vector维护了
我们大概可以把vector封装成这样的东西

struct Block_chain
{
    vector<int>v;
    inline void clear(){v.clear();}
    inline void ordered(){sort(v.begin(),v.end());}
    inline int size(){return v.size();}
    inline void insert(int x){v.push_back(x);}
    inline void modify(int x,int y)
    {
        vector<int>::iterator pos=lower_bound(v.begin(),v.end(),x);
        if(pos==v.end())return ;
        v.erase(pos);
        pos=lower_bound(v.begin(),v.end(),y);
        v.insert(pos,y);
    }
    inline void print(){for(register unsigned int i=0;i<v.size();i++)printf("%d ",v[i]);putchar(10);}
    inline int solve(int x){return v.end()-upper_bound(v.begin(),v.end(),x);}
    inline void order_insert(int x)
    {
        vector<int>::iterator pos=lower_bound(v.begin(),v.end(),x);
        v.insert(pos,x);
    }
};

这就是一个非常好用的容器了
那我们如何分块呢?
我们将每Block个点放在一个块链里。
并且将这些块链连成一棵新的树
易知一个点的子树里所有的点要不是和根在同一块里,要不就是其所在块整块都在子树中

void build_block(int u,int father)
{
    if(!father||A[belong[father]].size()>Block)
    {
        ++now;
        belong[u]=now;
        A[now].insert(a[u]);
        if(father)blo_add(belong[father],now);
    }
    else
    {
        belong[u]=belong[father];
        A[belong[u]].insert(a[u]);
    }
    fa[u]=father;
    for(register int i=head[u];i;i=e[i].nxxt)
    {
        if(e[i].to==fa[u])continue ;
        build_block(e[i].to,u);
    }
}

这样就可以重建一颗块状树了
查询时分情况讨论
如果在同一个块里,则暴力一个一个查询
如果不在一个块里,就整块查询
link时原图link,块状树也要link
贴代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<vector>
#include<cmath>
using namespace std;
const int MAXN=60010;
#define fastcall __attribute__((optimize("-O3")))
#define IL __inline__ __attribute__((always_inline))
fastcall IL char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
template<class T>fastcall IL void read(T &x)
{
    T s=0,w=1;
    char c=nc();
    while(!isdigit(c)){if(c=='-')w=-1;c=nc();}
    while(isdigit(c))s=(s<<3)+(s<<1)+c-'0',c=nc();
    x=s*w;
}
inline void write(int x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
struct edge
{
    int to,nxxt;
}e[MAXN<<2],blo[MAXN<<2];
struct Block_chain
{
    vector<int>v;
    inline void clear(){v.clear();}
    inline void ordered(){sort(v.begin(),v.end());}
    inline int size(){return v.size();}
    inline void insert(int x){v.push_back(x);}
    inline void modify(int x,int y)
    {
        vector<int>::iterator pos=lower_bound(v.begin(),v.end(),x);
        if(pos==v.end())return ;
        v.erase(pos);
        pos=lower_bound(v.begin(),v.end(),y);
        v.insert(pos,y);
    }
    inline void print(){for(register unsigned int i=0;i<v.size();i++)printf("%d ",v[i]);putchar(10);}
    inline int solve(int x){return v.end()-upper_bound(v.begin(),v.end(),x);}
    inline void order_insert(int x)
    {
        vector<int>::iterator pos=lower_bound(v.begin(),v.end(),x);
        v.insert(pos,x);
    }
}A[MAXN];
int head[MAXN],cnt,blo_head[MAXN],blo_cnt,belong[MAXN],a[MAXN],fa[MAXN],Block,now;
int n,m,opt;
inline void add(int x,int y)
{
    e[++cnt].to=y;
    e[cnt].nxxt=head[x];
    head[x]=cnt;
}
inline void blo_add(int x,int y)
{
    blo[++blo_cnt].to=y;
    blo[blo_cnt].nxxt=blo_head[x];
    blo_head[x]=blo_cnt;
}
inline void update(int u,int x)
{
    A[belong[u]].modify(a[u],x);
    a[u]=x;
}   
void build_block(int u,int father)
{
    if(!father||A[belong[father]].size()>Block)
    {
        ++now;
        belong[u]=now;
        A[now].insert(a[u]);
        if(father)blo_add(belong[father],now);
    }
    else
    {
        belong[u]=belong[father];
        A[belong[u]].insert(a[u]);
    }
    fa[u]=father;
    for(register int i=head[u];i;i=e[i].nxxt)
    {
        if(e[i].to==fa[u])continue ;
        build_block(e[i].to,u);
    }
}
int block_query(int u,int x)
{
    int ans=A[u].solve(x);
    for(register int i=blo_head[u];i;i=blo[i].nxxt)
    ans+=block_query(blo[i].to,x);
    return ans;
}
int solve(int u,int x)
{
    int ans=0;
    if(a[u]>x)ans++;
    for(register int i=head[u];i;i=e[i].nxxt)
    {
        if(e[i].to==fa[u])continue ;
        if(belong[u]==belong[e[i].to])ans+=solve(e[i].to,x);
        else ans+=block_query(belong[e[i].to],x);
    }
    return ans;
}
int lastans;
int main()
{
    read(n);
    for(register int i=1;i<n;i++)
    {
        int a,b;
        read(a),read(b);
        add(a,b),add(b,a);
    }
    for(register int i=1;i<=n;i++)read(a[i]);
    read(m);
    Block=ceil(sqrt(n+m));
    build_block(1,0);
    for(register int i=1;i<=now;i++)A[i].ordered();
    while(m--)
    {
        read(opt);
        int u,x;
        read(u),read(x);
        u^=lastans,x^=lastans;
        if(!opt)
            write(lastans=solve(u,x)),putchar(10);
        else if(opt==1)
            update(u,x);
        else
        {
            a[++n]=x;
            add(u,n),add(n,u);
            if(A[belong[u]].size()<Block)A[belong[u]].order_insert(x),belong[n]=belong[u];
            else A[++now].order_insert(x),blo_add(belong[u],now),belong[n]=now;
            fa[n]=u;
        }
    }
}

效率还行
luogu需要吸氧才能AC

猜你喜欢

转载自blog.csdn.net/assass_cannotin/article/details/80350469