BZOJ3786: 星系探索 Splay+DFS序
题目大意:给你一个树,支持三种操作,子树加,点到根的路径和,改变某一个点的父亲。
分析:
看起来像一个大LCT,但是很显然,LCT做子树加我不太会啊...
那么,考虑更换一个点的父亲这个操作很有意思,也就是说明,整个树的结构不会有什么大的变化,只是某个节点的父亲变了,那么也就是相当于在DFS序上顺序的变化,那么我们就可以考虑化简它的树结构,从而在序列上解决。
而对于这道题,DFS序能解决,但需要维护更多信息,而且乘法的次数多了很多次,没试,但是应该过不去。我们可以换一种序列,也就是入栈出栈序,这样就可以完美解决了。
我们动态的维护四个信息,Splay Tree该节点的子树大小,该节点的子树和,和子树正号数量-符号数量符号,Lazy标记。之后每次PushDown的时候用Lazy*num来更新sum。其他的照常。
关键是每次查询的时候,因为我们不论怎么改变这个序列,有一点从来没有变,就是对应的树上节点在Splay Tree上的节点标号,那么每次只需要找到前驱后继即可,而找到前驱后继显然最好还是用Query_rank和Query_x分别表示找到对应节点的排名和对应排名的节点编号,非递归,记得在Query_x的时候PushDown就可以了!
之后Rank1什么的,就不用在意了...毕竟Splay的常数...大家知道就好...
不过我已经尽力了...最快优化到33s,不知道还有没有其他优化...
附上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | #include <cstdio> #include <algorithm> #include <cmath> #include <cstring> #include <cstdlib> #include <queue> #include <iostream> using namespace std; #define N 200005 #define ll long long #define ls ch[rt][0] #define rs ch[rt][1] #define get(rt) (ch[f[rt]][0]!=rt) #define PushUp(rt) num[rt]=num[ch[rt][0]]+num[ch[rt][1]]+flag[rt],sum[rt]=sum[ch[rt][0]]+sum[ch[rt][1]]+val[rt]*flag[rt],siz[rt]=siz[ch[rt][0]]+siz[ch[rt][1]]+1 char buf[100000],*p1,*p2; #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++) __attribute__((optimize( "-O3" ))) int rd() { register int x=0; register char ch=nc(); while (ch< '0' ||ch> '9' ) ch=nc(); while (ch>= '0' &&ch<= '9' ) x=(x<<3)+(x<<1)+ch- '0' ,ch=nc(); return x; } struct node{ int to,next;}e[N]; int head[N],f[N],num[N],siz[N],cnt,flag[N],n,rot,ch[N][2],tmp,tims,a[N],idx[N],p[N]; ll sum[N]; int add[N],val[N]; void add1( int x, int y){e[cnt]=(node){y,head[x]},head[x]=cnt++;} void dfs( int x) { idx[++tims]=x;p[x]=tims; for ( int i=head[x];i!=-1;i=e[i].next)dfs(e[i].to); idx[++tims]=x+n;p[x+n]=tims; } void PushDown( int rt) { if (add[rt]) { sum[ls]+=( long long )(add[rt])*num[ls],val[ls]+=add[rt],add[ls]+=add[rt]; sum[rs]+=( long long )(add[rt])*num[rs],val[rs]+=add[rt],add[rs]+=add[rt]; add[rt]=0; } } void rotate( int rt) { int x=f[rt],y=f[x],k=get(rt); if (x!=rot)ch[y][ch[y][0]!=x]=rt; else rot=rt; ch[x][k]=ch[rt][!k];f[ch[x][k]]=x; ch[rt][!k]=x;f[x]=rt;f[rt]=y; PushUp(x);PushUp(rt); } void Splay( int rt, int y) { register int fa; for (;(fa=f[rt])!=y;rotate(rt)) if (f[fa]!=y) rotate((get(fa)==get(rt))?fa:rt); } void build( int fa, int l, int r) { if (l>r) return ; int m=(l+r)>>1; ch[fa][m>fa]=m;f[m]=fa;siz[m]=1; //printf("%d %d %d\n",idx[m],m,val[m]); build(m,l,m-1);build(m,m+1,r);PushUp(m); } int query_k( int rt) { int ret=0; while (rt) { // PushDown(rt); // printf("%d %d %d\n",x,idx[rt],ret); if (rt==rot)ret+=siz[ls]+1; else if (get(rt))ret+=siz[ls]+1; else ret-=siz[rs]+1; rt=f[rt]; } return ret; } int find( int x) { register int rt=rot; while (1) { PushDown(rt); if (x<=siz[ls])rt=ls; else { x-=siz[ls]+1; if (!x) return rt; rt=rs; } } } void cut( int x) { int rt=find(query_k(p[x+n])+1);x=find(query_k(p[x])-1); Splay(x,0);Splay(rt,rot);tmp=ls; ls=f[ls]=0;PushUp(rt);PushUp(x); } void link( int x) { int rt=find(query_k(p[x])+1);x=find(query_k(p[x])); Splay(x,0);Splay(rt,rot); // printf("%d %d\n",x,rt); ls=tmp;f[tmp]=rt;PushUp(rt);PushUp(x); } void Update( int x, int c) { int rt=find(query_k(p[x+n])+1);x=find(query_k(p[x])-1); Splay(x,0);Splay(rt,rot); add[ls]+=c;val[ls]+=c; } int query( int x) { int rt=find(query_k(p[x])+1);x=1; Splay(x,0);Splay(rt,rot); printf ( "%lld\n" ,sum[ls]); } char s[2]; int main() { n=rd(); memset (head,-1, sizeof (head)); for ( int i=2,x;i<=n;i++)add1(rd(),i); tims=1;dfs(1);idx[++tims]=tims;idx[1]=0; for ( int i=1;i<=n;i++)a[i]=rd(); for ( int i=2;i<=n*2+1;i++) { int x=idx[i]; if (x<=n)val[i]=a[x],flag[i]=1; else val[i]=a[x-n],flag[i]=-1; } build(0,1,2*n+2);rot=n+1; int Q=rd(); while (Q--) { char op=nc(); while (op!= 'C' &&op!= 'Q' &&op!= 'F' )op=nc(); int x=rd(); if (op== 'Q' )query(x); else if (op== 'C' ) { cut(x); link(rd()); } else Update(x,rd()); // print(); } return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步