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

题目大意:给你一棵树,支持一下三种操作

1.获取某节点到根节点的路径上所有节点的权值和

2.更换某棵子树的父亲

3.某子树内所有节点的权值都增加一个值w

当时想到了splay维护dfs序,查完题解发现思路是对的,然后我就写了足足6个小时才A

st[x]代表入栈时间,ed[x]代表出栈时间

对于第一个操作,每个树上节点在splay中都有两个位置,分别对应入栈出栈序,然后把入栈的点权*1,出栈点权*-1,就可以避免其它子树干扰了

接着查询到根节点的路径权值和呢,splay把1~st[x]整个序列都扔到一个子树里,求一下子树权值和即可

第二个操作,可以找一下st[x]和ed[x]对应splay中节点的前驱和后继,把它们都搞到一个splay子树里,在把整棵树接到要求的父节点即可

第三个操作,和第二个操作类似,找前驱后继然后在子树打标记即可,此外,还要维护splay子树内的入栈节点数-出栈节点数来直接得到splay子树的权值和。

注意,一定要在所有能传标记的地方都传标记,不论是从下往上splay,还是从上到下找前驱or后继,而如果不在找前驱后继的过程中下传标记,上层的标记无法被传到下层,导致结果错误!就这个错误我调了2个小时!

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #define N 200100
  5 #define il inline
  6 #define ll long long
  7 #define root d[0].ch[1]
  8 using namespace std;
  9
 10 char q[10];
 11 int n,m,cte,tot;
 12 int st[N],ed[N],head[N],sq[N];
 13 ll w[N];
 14 struct EDGE{int to,nxt;}edge[N];
 15 struct SPLAY{int fa,ch[2],ss,fl;ll val,sum,tag;}d[N];
 16 il int idf(int x){return d[d[x].fa].ch[0]==x?0:1;}
 17 il void con(int x,int ff,int p){d[ff].ch[p]=x;d[x].fa=ff;}
 18 il void pushup(int x){
 19     d[x].sum=d[d[x].ch[0]].sum+d[d[x].ch[1]].sum+d[x].val;
 20     d[x].ss=d[d[x].ch[0]].ss+d[d[x].ch[1]].ss+d[x].fl;
 21 }
 22 il void pushdown(int x){
 23     if(!d[x].tag) return;
 24     int ls=d[x].ch[0],rs=d[x].ch[1];
 25     d[ls].tag+=d[x].tag,d[rs].tag+=d[x].tag;
 26     d[ls].val+=d[x].tag*(ll)d[ls].fl,d[rs].val+=d[x].tag*(ll)d[rs].fl;
 27     d[ls].sum+=d[x].tag*(ll)d[ls].ss,d[rs].sum+=d[x].tag*(ll)d[rs].ss;
 28     d[x].tag=0;
 29 }
 30 il void rot(int x){
 31     int y=d[x].fa;int ff=d[y].fa;int px=idf(x);int py=idf(y);
 32     pushdown(y),pushdown(x);
 33     con(d[x].ch[px^1],y,px),con(y,x,px^1),con(x,ff,py);
 34     pushup(y),pushup(x);
 35 }
 36 il void splay(int x,int to){
 37     to=d[to].fa;
 38     while(d[x].fa!=to){
 39         int y=d[x].fa;
 40         if(d[y].fa==to) rot(x);
 41         else if(idf(x)==idf(y)) rot(y),rot(x);
 42         else rot(x),rot(x);}
 43 }
 44 int gc(){
 45     int rett=0,fh=1;char p=getchar();
 46     while(p<‘0‘||p>‘9‘){if(p==‘-‘)fh=-1;p=getchar();}
 47     while(p>=‘0‘&&p<=‘9‘){rett=(rett<<3)+(rett<<1)+p-‘0‘;p=getchar();}
 48     return rett*fh;
 49 }
 50 void ae(int u,int v){
 51     cte++;edge[cte].to=v;
 52     edge[cte].nxt=head[u];head[u]=cte;
 53 }
 54 void dfs1(int u,int ff)
 55 {
 56     st[u]=++tot,sq[tot]=u,d[tot].val=w[u],d[tot].fl=1;
 57     for(int j=head[u];j!=-1;j=edge[j].nxt){
 58         int v=edge[j].to;
 59         if(v==ff) continue;
 60         dfs1(v,u);}
 61     ed[u]=++tot,sq[tot]=u,d[tot].val=-w[u],d[tot].fl=-1;
 62 }
 63 int build(int l,int r)
 64 {
 65     if(l>r) return 0;
 66     int mid=(l+r)>>1;
 67     con(build(l,mid-1),mid,0);
 68     con(build(mid+1,r),mid,1);
 69     pushup(mid);
 70     return mid;
 71 }
 72 int lower(int x)
 73 {
 74     pushdown(x),x=d[x].ch[0];
 75     while(x){
 76         pushdown(x);
 77         if(d[x].ch[1]) x=d[x].ch[1];
 78         else break;}
 79     return x;
 80 }
 81 int upper(int x)
 82 {
 83     pushdown(x),x=d[x].ch[1];
 84     while(x){
 85         pushdown(x);
 86         if(d[x].ch[0]) x=d[x].ch[0];
 87         else break;}
 88     return x;
 89 }
 90 ll query(int x)
 91 {
 92     splay(st[0],root);
 93     splay(st[x],d[root].ch[1]);
 94     int lw=upper(st[x]);
 95     splay(lw,d[root].ch[1]);
 96     return d[d[lw].ch[0]].sum;
 97 }
 98 void add(int x,ll ww)
 99 {
100     int trl,trr,rt;
101     splay(st[x],root);
102     splay(ed[x],d[root].ch[1]);
103     trl=lower(st[x]);
104     splay(trl,root);
105     trr=upper(ed[x]);
106     splay(trr,d[root].ch[1]);
107     rt=d[trr].ch[0];
108     d[rt].val+=ww*(ll)d[rt].fl;
109     d[rt].sum+=ww*(ll)d[rt].ss;
110     d[rt].tag+=ww;
111 }
112 void mov(int x,int y)
113 {
114     int trl,trr,frt,rtt;
115     splay(st[x],root);
116     splay(ed[x],d[root].ch[1]);
117     trl=lower(st[x]);
118     splay(trl,root);
119     trr=upper(ed[x]);
120     splay(trr,d[root].ch[1]);
121     pushdown(trl),pushdown(trr);
122     rtt=d[trr].ch[0];
123     d[trr].ch[0]=0,d[rtt].fa=0;
124     pushup(trr),pushup(trl);
125
126     splay(st[y],root);
127     splay(ed[y],d[root].ch[1]);
128     trl=lower(ed[y]);
129     if(trl) con(rtt,trl,1);
130     else con(rtt,ed[y],0);
131     splay(rtt,root);
132 }
133 void print(int x)
134 {
135     if(d[x].ch[0]) print(d[x].ch[0]);
136     printf("%d ",sq[x]);
137     if(d[x].ch[1]) print(d[x].ch[1]);
138 }
139
140 int main()
141 {
142     scanf("%d",&n);
143     int x,y;
144     memset(head,-1,sizeof(head));
145     for(int i=2;i<=n;i++)
146         x=gc(),ae(x,i),ae(i,x);
147     for(int i=1;i<=n;i++)
148         w[i]=gc();
149     st[0]=++tot,dfs1(1,-1),ed[0]=++tot;
150     root=build(1,tot);
151     scanf("%d",&m);
152     for(int i=1;i<=m;i++){
153         scanf("%s",q);
154         if(q[0]==‘Q‘){
155             x=gc();
156             printf("%lld\n",query(x));
157         }else if(q[0]==‘F‘){
158             x=gc(),y=gc();
159             add(x,(ll)y);
160         }else{
161             x=gc(),y=gc();
162             mov(x,y);
163         }
164     }
165     /*for(int i=1;i<=n;i++)
166         printf("%lld %lld %lld\n",query(i),d[st[i]].val,d[ed[i]].val);*/
167     return 0;
168 }

原文地址:https://www.cnblogs.com/guapisolo/p/9697056.html

时间: 2024-10-10 06:29:11

bzoj 3786 星系探索 (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维护树的入栈出栈序

题目大意:给出一棵树,要求有以下这些操作:1.求出一个节点到根的点权和.2.将一个节点的父亲改变.3.将一个子树中的每一个节点都加上一个权值. 思路:LCT就不用想了,因为有子树操作.然后就是一个很神奇的东西了,就是Splay维护树的入栈出栈序.这个玩应是做了这个题之后才知道的.但是感觉真的很dio. 首先,我们先按照题意,将树建出来.然后从根开始深搜,这样一个点进入DFS函数和出DFS函数的时候就会有两个时间点,就是入栈的时间和出栈的时间.然后利用Splay维护一个序列,就是入栈出栈的顺序.在

[BZOJ 3786] 星系探索 Splay维护入栈出栈序

题意 给定一棵 n 个节点, 点有点权, 以 1 为根的有根树. m 次操作: ① 查询点 d 到根的点权之和. ② 将 x 及其子树截出来, 作为 y 的儿子. ③ 将以 p 为根的子树的点权增加 q . $n \le 100000$ . 实现 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include <vector>

bzoj 3786 星系探索 dfs+splay

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

BZOJ 3786 星系探索

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

bzoj3786 星际探索 splay dfs序

这道题 首先 因为他求的是当前点到根节点的路径和 我们可以将题目转换为括号序列的写法 将点拆为左括号以及右括号 左括号为正 右括号为负 这样题目就变为了求前缀和了 如果一个点是这个点的子树 那么他的左右括号就一定包含在所求区间里 会被抵消掉而不影响结果. 这样我们可以利用dfs序建树 操作为区间加 单点修改 树的合并以及分裂 一起区间和 当然区间加因为我们维护的是括号序列 所以区间加的时候我们就要将左括号加w而右括号减w 但是我们因此我们还要记录这个点子树及其本身的左右括号差 区间加就加上左括号

BZOJ 3786 星系探索 DFS序+Splay

题目大意:给定一棵有根树,提供下列操作: 1.询问某个点到根路径上的点权和 2.修改某个点的父亲,保证修改之后仍然是一棵树 3.将某个点所在子树的所有点权加上一个值 子树修改,LCT明显是搞不了了,在想究竟会不会有人去写自适应Top-Tree-- 首先我们DFS搞出这棵树的入栈出栈序 然后入栈为正出栈为负 那么一个点到根的路径上的点权和就是从根节点的入栈位置到这个点的入栈位置的和 子树修改就记录某段序列中有多少入栈和多少出栈,然后根据这个对这棵子树所在序列修改即可 那么换父亲操作呢?显然可以用S

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$的点旋转至根,答案就是