bzoj3786 星际探索 splay dfs序

这道题 首先 因为他求的是当前点到根节点的路径和 我们可以将题目转换为括号序列的写法 将点拆为左括号以及右括号 左括号为正 右括号为负 这样题目就变为了求前缀和了 如果一个点是这个点的子树 那么他的左右括号就一定包含在所求区间里 会被抵消掉而不影响结果。 这样我们可以利用dfs序建树 操作为区间加 单点修改 树的合并以及分裂 一起区间和 当然区间加因为我们维护的是括号序列 所以区间加的时候我们就要将左括号加w而右括号减w 但是我们因此我们还要记录这个点子树及其本身的左右括号差 区间加就加上左括号数减右括号数的差 乘以w就可以了 当然还要维护这两个括号本身的信息 毕竟这是一个闭区间   区间的分裂和合并的话 (左括号为x 右括号为y) 将x旋到root 切开他的左子树 左子树根为p1 将y旋到root 切开他的右子树 右子树跟为p3 xy所在的树跟为p3 然后将p1和p3合并 合并的话将p1的树上最右下方的点旋到p1 这样他就不存在右子树 强制将p3连到右子树 然后将新的依赖关系的点k旋到p1 切开右子树 强制讲p2连到右子树 然后按前面的方法把剩下的两棵树连在一起 就okay了 说起来难其实就三个函数的事情 不超过二十行 看代码比较好理解呐 剩下的加油咯

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=600555;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<‘0‘||c>‘9‘){if(c==‘-‘) f=-1; c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){ans=ans*10+(c-‘0‘); c=getchar();}
    return ans*f;
}
long long tag[M],v[M],ans[M];
int tot,n,m,root,d[M],q[M],fa[M],pd[M];
int first[M],sum,c[M][2];
struct node{int to,next,w;}e[M];
void insert(int a,int b){sum++; e[sum].to=b; e[sum].next=first[a]; first[a]=sum;}
void add(int z,long long w){
    if(!z) return ;
    tag[z]+=w;
    v[z]+=w*pd[z];
    ans[z]+=w*d[z];
}
void qadd(int z,int w){
    if(!z) return ;
    v[z]+=w*pd[z];
    ans[z]+=w*pd[z];
}
void up(int k){
    int l=c[k][0],r=c[k][1];
    d[k]=pd[k]+d[l]+d[r];
    ans[k]=ans[l]+ans[r]+v[k];
}
void down(int k){
    if(tag[k]){
        add(c[k][0],k[tag]);
        add(c[k][1],k[tag]);
        tag[k]=0;
    }
}
void rotate(int x,int& k){
    int y=fa[x],z=fa[y],l=0,r=1;
    if(c[y][1]==x) l=1,r=0;
    if(y==k) k=x;
    else{if(c[z][0]==y) c[z][0]=x; else c[z][1]=x;}
    fa[y]=x; fa[x]=z; fa[c[x][r]]=y;
    c[y][l]=c[x][r]; c[x][r]=y;
    up(y); up(x);
}
int stk[M],stp=0;
void sp(int x,int& k){
    for(int w=x;w;w=w[fa])stk[stp++]=w;
    while(stp)down(stk[--stp]);
    while(x!=k){
        int y=fa[x],z=fa[y];
        if(y!=k){
            if(c[z][0]==y^c[y][0]==x) rotate(y,k);
            else rotate(x,k);
        }
        rotate(x,k);
    }
}
void dfs(int k){
    q[++tot]=k;
    for(int i=first[k];i;i=e[i].next) dfs(e[i].to);
    q[++tot]=k+n;
}
int build(int l,int r){
    if(l>r) return 0;
    int m=(l+r)>>1,now=q[m];
    c[now][0]=build(l,m-1);
    c[now][1]=build(m+1,r);
    for(int i=0;i<2;i++) if(c[now][i]) fa[c[now][i]]=now;
    up(now);
    return now;
}
int find(int k){
    while(c[k][1]) k=c[k][1];
    return k;
}
void cut_l(int x,int rt,int& r1,int& r2){
    sp(x,rt);
    r1=c[x][0]; r2=x;
    c[r2][0]=fa[r1]=0;
    up(x);
}
void cut_r(int x,int rt,int& r1,int& r2){
    sp(x,rt);
    r1=x; r2=c[x][1];
    c[r1][1]=fa[r2]=0;
    up(x);
}
int mg(int r1,int r2){
    int w=find(r1);
    sp(w,r1);
    c[w][1]=r2;fa[r2]=w;
    up(w);
    return w;
}
void papa(int x,int f){
    int y=x+n,p1,p2,p3;
    cut_l(x,root,p1,p2);
    cut_r(y,p2,p2,p3);
    cut_r(f,mg(p1,p3),p1,p3);
    root=mg(mg(p1,p2),p3);
}
int main()
{
    int k,w;
    char ch[10];
    n=read();
    for(int i=2;i<=n;i++) k=read(),insert(k+1,i+1);
    for(int i=2;i<=n+1;i++) w=read(),v[i]=w,v[i+n]=-w,pd[i]=1,pd[i+n]=-1;
    q[++tot]=1; dfs(2); q[++tot]=2*n+2;
    root=build(1,2*n+2);
    m=read();
    while(m--){
        scanf("%s",ch);
        if(ch[0]==‘Q‘){k=read()+1; sp(k,root); printf("%lld\n",ans[c[k][0]]+v[k]);}
        if(ch[0]==‘C‘){ int x=read()+1,y=read()+1; papa(x,y);}
        if(ch[0]==‘F‘){
            k=read()+1; w=read();
            int y=k+n,z;
            sp(k,root); sp(y,c[root][1]);
            z=c[y][0];
            qadd(k,w); qadd(y,w);
            add(z,w);
            up(y); up(k);
        }
    }
    return 0;
}

时间: 2024-10-10 04:29:13

bzoj3786 星际探索 splay dfs序的相关文章

【BZOJ-3786】星系探索 Splay + DFS序

3786: 星系探索 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 647  Solved: 212[Submit][Status][Discuss] Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球没有依赖星球. 我们定义依赖关系如下:若星球a的依赖星球是b,则有星球a依赖星球b.此外,依赖关系

bzoj 3786 星系探索 (splay+dfs序)

题目大意:给你一棵树,支持一下三种操作 1.获取某节点到根节点的路径上所有节点的权值和 2.更换某棵子树的父亲 3.某子树内所有节点的权值都增加一个值w 当时想到了splay维护dfs序,查完题解发现思路是对的,然后我就写了足足6个小时才A st[x]代表入栈时间,ed[x]代表出栈时间 对于第一个操作,每个树上节点在splay中都有两个位置,分别对应入栈出栈序,然后把入栈的点权*1,出栈点权*-1,就可以避免其它子树干扰了 接着查询到根节点的路径权值和呢,splay把1~st[x]整个序列都扔

bzoj3786星系探索 splay

3786: 星系探索 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1314  Solved: 425[Submit][Status][Discuss] Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球没有依赖星球. 我们定义依赖关系如下:若星球a的依赖星球是b,则有星球a依赖星球b.此外,依赖关

Bzoj3786: 星系探索——Splay

题面  Bzoj3786 解析  上课讲稿上的例题 这道题是套路题,是括号序的应用,进入节点时打上$+1$标记, 退出时打上$-1$标记,这个是作为点权的系数 先看操作2, 需要更改父节点,就是把一段区间提取出来,插入另一个地方,显然可以用Splay维护,先提取区间,再把新父亲的$+1$点旋转至根,把区间挂在根的后继的左儿子上,再把这个节点旋转至根,以更新信息 对于操作1,求点到根的路径和,就是求括号序列的前缀和,该点对应的$+1$点或$-1$点的前缀和都可,我是把$-1$的点旋转至根,答案就是

【BZOJ3786】星系探索 DFS序+Splay

[BZOJ3786]星系探索 Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球没有依赖星球. 我们定义依赖关系如下:若星球a的依赖星球是b,则有星球a依赖星球b.此外,依赖关系具有传递性,即若星球a依赖星球b,星球b依赖星球c,则有星球a依赖星球c. 对于这个神秘的星系中,小C初步探究了它的性质,发现星球之间的依赖关系是无环的.并且从星球a出发只

【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒.实验在一个封闭的局域网内进行.局域网内有n台计算机,编号为1~n.一些计算机之间通过网线直接相连,形

Bzoj3786 星系探索

Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1036  Solved: 342 Description 物理学家小C的研究正遇到某个瓶颈. 他正在研究的是一个星系,这个星系中有n个星球,其中有一个主星球(方便起见我们默认其为1号星球),其余的所有星球均有且仅有一个依赖星球.主星球没有依赖星球. 我们定义依赖关系如下:若星球a的依赖星球是b,则有星球a依赖星球b.此外,依赖关系具有传递性,即若星球a依赖星球b,星球b依赖星球c,则有星球a依赖星球

BZOJ 3779 重组病毒 LCT+线段树维护DFS序

题目大意:给定一棵树,初始每个点都有一个颜色,支持三种操作: 1.将某个点到根的路径上所有点染上一种新的颜色 2.将某个点到根的路径上所有点染上一种新的颜色,然后把根设为这个点 3.定义一个点的代价为这个点到根路径上颜色的种类数,求某个点子树中所有点代价的平均值 我真是炖了狗了-- 容易发现这玩应就是个LCT,操作1就是Access,操作2就是Move_To_Root,代价就是一个点到根路径上的虚边数量+1 我们用LCT模拟上述操作,用线段树维护DFS序维护信息,一旦LCT中出现了虚实边的切换,

【BZOJ3779】重组病毒 LCT+DFS序

[BZOJ3779]重组病毒 Description 黑客们通过对已有的病毒反编译,将许多不同的病毒重组,并重新编译出了新型的重组病毒.这种病毒的繁殖和变异能力极强.为了阻止这种病毒传播,某安全机构策划了一次实验,来研究这种病毒.实验在一个封闭的局域网内进行.局域网内有n台计算机,编号为1~n.一些计算机之间通过网线直接相连,形成树形的结构.局域网中有一台特殊的计算机,称之为核心计算机.根据一些初步的研究,研究员们拟定了一个一共m步的实验.实验开始之前,核心计算机的编号为1,每台计算机中都有病毒