[bzoj3786] 星系探索
这道题搞了好几天......当然不是一直在搞,中间考了场试,改了改考试题......
这题先写的东西觉得思路太混乱,翻了翻题解之后思路清晰了一些,重构了。
这道题思路很清楚:用splay维护入栈出栈序。
对于子树修改的操作,splay之后,打标记。
对于换根的操作,splay之后把整个子树拿下来,再splay,最后再接到上面。
在入栈出栈序的体现就是区间的平移:1 2 3 3 2 4 4 1 --> 1 2 2 4 3 3 4 1 (此为把3的根从2换成4)。
查询操作就是查询入栈出栈序上,in[p]的前缀和。
具体写的话就比较复杂了,码量比较大。
解释代码里几个名称:
empty就是指空位置,由于0有用,所以不能用0作为空位置。
我们可以让没用到的n*2+2作为空位置的标志。
in,out入栈出栈。
fl标记是正是负,入栈处为正,出栈处为负。
sz不是指splay中的子树大小,而是子树中fl的和。
v指节点值,sum指splay中子树的v的和。
lz为懒惰标记。
注意要开long long。
1 #include<cstdio> 2 #define empty 2*n+2 3 #define ll long long 4 #define id(x) (s[f[x]][1]==x) 5 6 int n,m; 7 int hd[100005],nx[200010],to[200010],ec; 8 int in[100005],out[100005],iv[100005]; 9 int s[200010][2],f[200010],root; 10 ll v[200010],sum[200010],lz[200010]; 11 int fl[200010],sz[200010]; 12 int dc; 13 14 void dfs(int p) 15 { 16 in[p]=++dc; 17 v[dc]=sum[dc]=iv[p]; 18 sz[dc]=fl[dc]=1; 19 for(int i=hd[p];i;i=nx[i])dfs(to[i]); 20 out[p]=++dc; 21 v[dc]=sum[dc]=-iv[p]; 22 sz[dc]=fl[dc]=-1; 23 } 24 25 void pushup(int p) 26 { 27 sum[p]=sum[s[p][0]]+sum[s[p][1]]+v[p]; 28 sz[p]=sz[s[p][0]]+sz[s[p][1]]+fl[p]; 29 } 30 31 int build(int l,int r) 32 { 33 if(l>r)return empty; 34 int mid=(l+r)>>1; 35 s[mid][0]=build(l,mid-1); 36 s[mid][1]=build(mid+1,r); 37 if(s[mid][0]!=empty)f[s[mid][0]]=mid; 38 if(s[mid][1]!=empty)f[s[mid][1]]=mid; 39 pushup(mid); 40 return mid; 41 } 42 43 void pushdown(int p) 44 { 45 if(!lz[p])return; 46 if(s[p][0]!=empty) 47 { 48 sum[s[p][0]]+=sz[s[p][0]]*lz[p]; 49 v[s[p][0]]+=fl[s[p][0]]*lz[p]; 50 lz[s[p][0]]+=lz[p]; 51 } 52 if(s[p][1]!=empty) 53 { 54 sum[s[p][1]]+=sz[s[p][1]]*lz[p]; 55 v[s[p][1]]+=fl[s[p][1]]*lz[p]; 56 lz[s[p][1]]+=lz[p]; 57 } 58 lz[p]=0; 59 } 60 61 void rotate(int p) 62 { 63 int fa=f[p]; 64 int k=id(p); 65 s[fa][k]=s[p][!k]; 66 s[p][!k]=fa; 67 s[f[fa]][id(fa)]=p; 68 f[p]=f[fa]; 69 f[s[fa][k]]=fa; 70 f[fa]=p; 71 pushup(fa); 72 pushup(p); 73 } 74 75 void update(int p) 76 { 77 if(p!=root)update(f[p]); 78 pushdown(p); 79 } 80 81 void splay(int p,int g) 82 { 83 update(p); 84 while(f[p]!=g) 85 { 86 int fa=f[p]; 87 if(f[fa]==g) 88 { 89 rotate(p); 90 break; 91 } 92 if(id(p)^id(fa))rotate(p); 93 else rotate(fa); 94 rotate(p); 95 } 96 if(g==empty)root=p; 97 } 98 99 int pre(int p) 100 { 101 if(s[p][0]!=empty) 102 { 103 for(p=s[p][0];s[p][1]!=empty;p=s[p][1]); 104 return p; 105 } 106 while(id(p)==0)p=f[p]; 107 return f[p]; 108 } 109 110 int post(int p) 111 { 112 if(s[p][1]!=empty) 113 { 114 for(p=s[p][1];s[p][0]!=empty;p=s[p][0]); 115 return p; 116 } 117 while(id(p)==1)p=f[p]; 118 return f[p]; 119 } 120 121 void quary() 122 { 123 int x; 124 scanf("%d",&x); 125 splay(post(in[x]),empty); 126 printf("%lld\n",sum[s[root][0]]); 127 } 128 129 void change() 130 { 131 int x,y; 132 scanf("%d%d",&x,&y); 133 splay(pre(in[x]),empty); 134 splay(post(out[x]),root); 135 int tar=s[root][1]; 136 int tmp=s[tar][0]; 137 s[tar][0]=empty; 138 f[tmp]=empty; 139 sz[tar]-=sz[tmp]; 140 sum[tar]-=sum[tmp]; 141 sz[root]-=sz[tmp]; 142 sum[root]-=sum[tmp]; 143 splay(in[y],empty); 144 splay(post(in[y]),root); 145 tar=s[root][1]; 146 s[tar][0]=tmp; 147 f[tmp]=tar; 148 pushup(tar); 149 pushup(root); 150 } 151 152 void flux() 153 { 154 int x,y; 155 scanf("%d%d",&x,&y); 156 splay(pre(in[x]),empty); 157 splay(post(out[x]),root); 158 int tar=s[s[root][1]][0]; 159 lz[tar]+=y; 160 sum[tar]+=sz[tar]*y; 161 v[tar]+=fl[tar]*y; 162 tar=f[tar]; 163 pushup(tar); 164 pushup(root); 165 } 166 167 int main() 168 { 169 scanf("%d",&n); 170 for(int i=2;i<=n;i++) 171 { 172 int t; 173 scanf("%d",&t); 174 to[++ec]=i; 175 nx[ec]=hd[t]; 176 hd[t]=ec; 177 } 178 for(int i=1;i<=n;i++)scanf("%d",&iv[i]); 179 for(int i=0;i<=2*n+1;i++)f[i]=s[i][0]=s[i][1]=empty; 180 dfs(1); 181 root=build(0,2*n+1); 182 scanf("%d",&m); 183 while(m--) 184 { 185 char op[5]; 186 scanf("%s",op+1); 187 if(op[1]=='Q')quary(); 188 if(op[1]=='C')change(); 189 if(op[1]=='F')flux(); 190 } 191 return 0; 192 }