BZOJ 3731 3731: Gty的超级妹子树 [树上size分块 !]

传送门

题意:一棵树,询问子树中权值大于k的节点个数,修改点权值,插入新点,断开边;强制在线


该死该死该死!!!!!!

MD我想早睡觉你知不知道

该死该死沙比提

断开边只会影响一个块,重构这个块就行了

如果断开的点$u$是这个块$p$的根,只修改原图和块图就好了

否则,把$u$子树在块中的部分从$p$里删除,放到一个新块里。并且,这些点连到的其他块的点,也要在块图上与$p$断开与新块相连

所以我们维护一个删除边的$mark$标记

WA:一开始原图加的是双向边,通过判断$fa$防止出错..后来$fa$会变化,然后判断$fa$就失灵了应该会一直$dfs$停不下来

所以一开始$dfs$就给双向边不用的那一条打上$mark$标记就好了

ps:读入挂我直接复制了PoPoQQQ大爷的因为我有一次以为是读入导致WA

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
typedef long long ll;
const int N=2e5+5;
inline int read1(){
    char c=getchar();int x=0,f=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
    return x*f;
}
namespace IOStream{
    const int L=1<<15;
    char buffer[L];
    char *S,*T;
    char Get_Char()
    {
        if(S==T)
        {
            T=(S=buffer)+fread(buffer,1,L,stdin);
            if(S==T)
                return EOF;
        }
        return *S++;
    }
    int Get_Int()
    {
        int re=0;
        char c;
        do c=Get_Char(); while(c<‘0‘||c>‘9‘);
        while(c>=‘0‘&&c<=‘9‘)
            re=(re<<1)+(re<<3)+(c-‘0‘),c=Get_Char();
        return re;
    }
}
#define read IOStream::Get_Int

int n,Q,a[N],op,u,x;

struct meow{
    vector<int> a;
    inline void set() {sort(a.begin(), a.end());}
    inline int count(int v) {return a.size() - (upper_bound(a.begin(), a.end(), v) - a.begin());}
    inline void push(int v) {a.push_back(v);}
    inline void insert(int v) {a.insert(lower_bound(a.begin(), a.end(), v), v);}
    inline void erase(int v) {a.erase(lower_bound(a.begin(), a.end(), v));}
    inline void replace(int x,int v) {if(x==v) return; erase(x); insert(v);}
    inline int size() {return a.size();}
}b[N];
int m, pos[N], block;

struct Graph4Block{
    struct edge{int v,ne;} e[N<<1];
    int cnt, h[N], ine[N], mark[N<<1];
    inline void ins(int u,int v) {
        e[++cnt]=(edge){v,h[u]}; h[u]=cnt;
        ine[v]=cnt;
    }
    inline void dele(int u) {mark[ine[u]]=1;}
    int dfs(int u,int k) {
        int ans= b[u].count(k);
        for(int i=h[u];i;i=e[i].ne) if(!mark[i]) ans+=dfs(e[i].v, k);
        return ans;
    }
}G;

struct edge{int v,ne;} e[N<<1];
int cnt, h[N];
inline void ins(int u,int v) {
    e[++cnt]=(edge){v,h[u]}; h[u]=cnt;
    e[++cnt]=(edge){u,h[v]}; h[v]=cnt;
}
int fa[N], mark[N<<1], ine[N];
inline void ins1(int u,int v) {
    e[++cnt]=(edge){v,h[u]}; h[u]=cnt;
    ine[v]=cnt; fa[v]=u;
}
inline void dele(int u) {fa[u]=0; mark[ine[u]]=1;}

void dfs(int u) {
    int p=pos[u];
    b[p].push(a[u]);
    for(int i=h[u];i;i=e[i].ne) if(!mark[i]) {
        if(e[i].v!=fa[u]) {
            fa[e[i].v]=u; ine[e[i].v]=i;
            if(b[p].size() < block) pos[e[i].v]=p;
            else pos[e[i].v]=++m, G.ins(p, m);
            dfs(e[i].v);
        } else mark[i]=1;
    }
}

struct Block{
    int dfs(int u,int k) {
        int ans= a[u]>k;
        for(int i=h[u];i;i=e[i].ne) if(!mark[i])
            if(e[i].v!=fa[u]) {
                if(pos[e[i].v] == pos[u]) ans+= dfs(e[i].v, k);
                else ans+= G.dfs(pos[e[i].v], k);
            }
        return ans;
    }
    int Que(int u, int k) {return dfs(u, k);}

    void Cha(int u, int d) {b[pos[u]].replace(a[u], d); a[u]=d;}

    void Ins(int u, int d) {
        a[++n]=d; ins1(u, n);
        int p=pos[u];
        if(b[p].size() < block) pos[n]=p, b[p].insert(a[n]);
        else pos[n]=++m, b[m].push(a[n]), G.ins(p, m);
    }

    void dfsSpl(int u,int p) {
        b[p].erase(a[u]); pos[u]=m; b[m].push(a[u]);
        for(int i=h[u];i;i=e[i].ne) if(!mark[i])
            if(e[i].v!=fa[u]) {
                if(pos[e[i].v] == p) dfsSpl(e[i].v, p);
                else G.dele(pos[e[i].v]), G.ins(m, pos[e[i].v]);
            }
    }
    void Split(int u){
        int p=pos[u];
        if(pos[fa[u]] != p)  G.dele(p);
        else m++, dfsSpl(u, p), b[m].set();
        dele(u);
    }
}B;
int main() {
    freopen("in", "r", stdin);
    n=read();
    for(int i=1;i<n;i++) ins(read(), read() );
    for(int i=1;i<=n;i++) a[i]=read();
    block= pow(n, 0.6);
    pos[1]=++m; dfs(1);
    for(int i=1;i<=m;i++) b[i].set();

    Q=read(); int lastans=0;
    for(int i=1;i<=Q;i++) {
        op=read();
        u=read()^lastans;
        if(op==3) B.Split(u);
        else{
            x=read()^lastans;
            if(op==0) lastans=B.Que(u, x), printf("%d\n",lastans);
            else if(op==1) B.Cha(u, x);
            else B.Ins(u, x);
        }
    }
}
时间: 2024-10-24 14:46:42

BZOJ 3731 3731: Gty的超级妹子树 [树上size分块 !]的相关文章

BZOJ 3720: Gty的妹子树 [树上size分块]

传送门 题意: 一棵树,询问子树中权值大于$k$的节点个数,修改点权值,插入新点:强制在线 一开始以为询问多少种不同的权值,那道CF的强制在线带修改版,直接吓哭 然后发现看错了这不一道树上分块水题... 用王室联邦分块的话需要维护每一个块$dfs$序最小值和最大值,并且插入操作会破坏原来的性质 不如直接按$size$分块,根节点$size<block$就加入根,否则新建块 $size$分块不能保证块的数量,可以被菊花图卡掉,然而本题没有所以就可以安心的写了 每个块维护排序后的值 查询操作,不完整

BZOJ 3731 Gty的超级妹子树 块状树

题目大意:同3720 增加了一个操作 即删除一个点与父亲节点的连边 3720题解见 http://blog.csdn.net/popoqqq/article/details/41481439 断开一个节点与父节点的连边时 如果这个点是所在块的根节点,直接断掉就行 如果这个点不是所在块的根节点,那么就要把这个块分裂,这个点以及在块中的子树都分裂到新的块中,细节讨论较多不大好写0.0 然后是一些小问题 1.此题卡内存 静态不用想了 开vector吧 2.是我常数写渣了还是这题真的卡时间0.0 之前是

BZOJ 3720 Gty的妹子树 树上分块

题目大意:给出一棵树,要求维护:1.求出以x为根节点的子树的严格大于y的数量. 2.将一个节点的权值改变. 3.在一个节点下加一个权值为y的节点. 思路:分块这个东西太神了(别找我分析时间复杂度..树上的分块更神... 首先,分块的原则和正常分块一样,把一棵树分成√n块,每一块不超过√n个,然后所有的时间复杂度降到了O(√n),(这个题还有个排序,所以还有一个log(n)). 如何在树上分块.规定根节点在编号为1的块中,然后做一次深搜,如果遍历到的一个节点的时候当前节点所在的块的数量已经达到最大

【BZOJ3720】Gty的妹子树 块状树

[BZOJ3720]Gty的妹子树 我曾在弦歌之中听过你,檀板声碎,半出折子戏.舞榭歌台被风吹去,岁月深处尚有余音一缕……Gty神(xian)犇(chong)从来不缺妹子……他来到了一棵妹子树下,发现每个妹子有一个美丽度……由于Gty很哲♂学,他只对美丽度大于某个值的妹子感兴趣.他想知道某个子树中美丽度大于k的妹子个数.某个妹子的美丽度可能发生变化……树上可能会出现一只新的妹子……维护一棵初始有n个节点的有根树(根节点为1),树上节点编号为1-n,每个点有一个权值wi.支持以下操作:0 u x 

BZOJ 1452: [JSOI2009]Count (二维树状数组)

Description Input Output Sample Input Sample Output 1 2 HINT 二维树状数组的简单应用,c数组的第一维坐标相当于哈希.如果是修改操作,修改前 将当前的值的个数以及祖先都减1, 修改后将个数加1. #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <set> #include

【BZOJ 1036】【ZJOI 2008】树的统计

此题为树链剖分的裸题. 代码如下,使用常用的轻重链剖分. /************************************************************** Problem: 1036 User: Evensgn Language: C++ Result: Accepted Time:2468 ms Memory:5772 kb ****************************************************************/ #inc

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

BNU 49100超级线段树

超级线段树 Time Limit: 5000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main Prev Submit Status Statistics Discuss Next Font Size:  +   - Type:   None Graph Theory      2-SAT     Articulation/Bridge/Biconnected Component  

【BZOJ】1012: [JSOI2008]最大数maxnumber(树状数组+区间最值)

http://www.lydsy.com/JudgeOnline/problem.php?id=1012 树状数组原来我只懂得sum和add的操作,今天才知道可以有求区间最值的操作,我学习了一下写了个,1a了. 区间最值其实和区间求和差不多,就是将sum数组的含义转移到max,然后通过特定的区间更新max. 在区间求和中,当我们维护max[i]的时候,要找到它前面所有的max[j]来更新,在这里因为是树状数组,所以可以降成一个log级,画图可知,max[i]需要的max只有max[i-2^0],