BZOJ3159: 决战(FHQ Treap)
传送门:
解题思路:
算是补坑了,这题除了Invert以外就可以树剖线段树解决了。
考虑Invert操作,延续先前树链剖分的做法,考虑先前算法的瓶颈。
最暴力的方法是暴力交换权值,然而这种方法忽略了当前树链剖分序的一个性质,那就是很多部分的树链是连续的,而且仅有$O(\lg n)$个区间。
考虑只有一个区间的做法,就很显然是区间翻转(这个不会搞的话你是怎么做到这道题的),于是,由于区间个数并不多,我们大胆猜想:正确的解法就是考虑翻如何转这些不连续区间
由于链区间具有一定的连续性,且我们需要翻转其权值,考虑更换我们所使用的数据结构,Splay和FHQ Treap都可以,我个人更倾向于使用后者(因为好写)。
现在问题瓶颈就是如何翻转不连续的区间权值。
其实方法很简单,将这$O(\lg n)$个拼接在一起,翻转,再重新安回去,很显然这样做的时间复杂度是$O((\lg n)^2))$的。
考虑具体的操作,由于下标索引在拆树的时候可能改变非常恶心,所以我们预处理出x-y中所有链区间,按dfs序排序,倒着拆,把x到lca上的树链翻转后拼接,再与y到lca上的树链翻转。最后再翻转,正着安回去。
大概就可以愉快地AC了。
代码:
1 #include<cstdio>
2 #include<cstring>
3 #include<cstdlib>
4 #include<algorithm>
5 #define lll tr[spc].ls
6 #define rrr tr[spc].rs
7 typedef long long lnt;
8 struct chain{
9 int ind;
10 int len;
11 bool x;
12 }ch[100010];
13 struct trnt{
14 int ls,rs;
15 int lzt;
16 int wgt;
17 int rnd;
18 lnt lzta;
19 lnt val;
20 lnt sum;
21 lnt maxval,minval;
22 void rediff(int seed){
23 ls=rs=lzt=0;
24 lzta=val=sum=maxval=minval=0;
25 rnd=seed+rand()%500+1;
26 wgt=1;
27 return ;
28 }
29 }tr[1000010];
30 struct pnt{
31 int hd;
32 int fa;
33 int tp;
34 int dep;
35 int ind;
36 int mxs;
37 int wgt;
38 }p[100010];
39 struct ent{
40 int twd;
41 int lst;
42 }e[100010];
43 int cnt;
44 int siz;
45 int dfn;
46 int top;
47 int n,m,r;
48 char cmd[100];
49 int rootl,rootr,rootm,root;
50 int pos[100010],size[100010];
51 int cmp(chain a,chain b){
52 return a.ind<b.ind;
53 }
54 void ade(int f,int t){
55 cnt++;
56 e[cnt].twd=t;
57 e[cnt].lst=p[f].hd;
58 p[f].hd=cnt;
59 return ;
60 }
61 void push_up(int spc){
62 tr[spc].wgt=1;
63 tr[spc].minval=tr[spc].maxval=tr[spc].sum=tr[spc].val;
64 if(lll){
65 tr[spc].wgt+=tr[lll].wgt;
66 tr[spc].sum+=tr[lll].sum;
67 tr[spc].minval=std::min(tr[spc].minval,tr[lll].minval);
68 tr[spc].maxval=std::max(tr[spc].maxval,tr[lll].maxval);
69 }
70 if(rrr){
71 tr[spc].wgt+=tr[rrr].wgt;
72 tr[spc].sum+=tr[rrr].sum;
73 tr[spc].minval=std::min(tr[spc].minval,tr[rrr].minval);
74 tr[spc].maxval=std::max(tr[spc].maxval,tr[rrr].maxval);
75 }
76 return ;
77 }
78 void add(int spc,lnt val){
79 if(!spc){
80 return ;
81 }
82 tr[spc].val+=val;
83 tr[spc].lzta+=val;
84 tr[spc].maxval+=val;
85 tr[spc].minval+=val;
86 tr[spc].sum+=val*tr[spc].wgt;
87 return ;
88 }
89 void trr(int spc){
90 if(!spc){
91 return ;
92 }
93 std::swap(lll,rrr);
94 tr[spc].lzt^=1;
95 return ;
96 }
97 void push_down(int spc){
98 if(tr[spc].lzt){
99 trr(lll);
100 trr(rrr);
101 tr[spc].lzt=0;
102 }
103 if(tr[spc].lzta){
104 add(lll,tr[spc].lzta);
105 add(rrr,tr[spc].lzta);
106 tr[spc].lzta=0;
107 }
108 return ;
109 }
110 void build(int l,int r,int &spc,int seed){
111 if(l>r){
112 return ;
113 }
114 int mid=(l+r)>>1;
115 spc=++siz;
116 tr[spc].rediff(seed);
117 build(l,mid-1,lll,tr[spc].rnd);
118 build(mid+1,r,rrr,tr[spc].rnd);
119 push_up(spc);
120 return ;
121 }
122 void split(int spc,int &ll,int &rr,int k){
123 if(!spc){
124 ll=rr=0;
125 return ;
126 }
127 push_down(spc);
128 if(tr[lll].wgt<k){
129 ll=spc;
130 split(rrr,rrr,rr,k-tr[lll].wgt-1);
131 }else{
132 rr=spc;
133 split(lll,ll,lll,k);
134 }
135 push_up(spc);
136 return ;
137 }
138 int merge(int ll,int rr){
139 if(!ll||!rr){
140 return ll|rr;
141 }else{
142 if(tr[ll].rnd<tr[rr].rnd){
143 push_down(ll);
144 tr[ll].rs=merge(tr[ll].rs,rr);
145 push_up(ll);
146 return ll;
147 }else{
148 push_down(rr);
149 tr[rr].ls=merge(ll,tr[rr].ls);
150 push_up(rr);
151 return rr;
152 }
153 }
154 return 0;
155 }
156 void Basic_dfs(int x,int f){
157 p[x].fa=f;
158 p[x].wgt=1;
159 p[x].dep=p[f].dep+1;
160 int maxs(-1);
161 for(int i=p[x].hd;i;i=e[i].lst){
162 int to=e[i].twd;
163 if(to==f){
164 continue;
165 }
166 Basic_dfs(to,x);
167 p[x].wgt+=p[to].wgt;
168 if(p[to].wgt>maxs){
169 p[x].mxs=to;
170 maxs=p[to].wgt;
171 }
172 }
173 return ;
174 }
175 void Build_dfs(int x,int t){
176 if(!x){
177 return ;
178 }
179 p[x].tp=t;
180 p[x].ind=++dfn;
181 Build_dfs(p[x].mxs,t);
182 for(int i=p[x].hd;i;i=e[i].lst){
183 int to=e[i].twd;
184 if(p[to].ind){
185 continue;
186 }
187 Build_dfs(to,to);
188 }
189 return ;
190 }
191 void Increase(int x,int y,lnt z){
192 while(p[x].tp!=p[y].tp){
193 if(p[p[x].tp].dep<p[p[y].tp].dep){
194 std::swap(x,y);
195 }
196 int S(p[p[x].tp].ind-1),T(p[x].ind);
197 split(root,rootl,rootr,T);
198 split(rootl,rootl,rootm,S);
199 add(rootm,z);
200 root=merge(rootl,merge(rootm,rootr));
201 x=p[p[x].tp].fa;
202
203 }
204 if(p[x].dep>p[y].dep){
205 std::swap(x,y);
206 }
207 int S(p[x].ind-1),T(p[y].ind);
208 split(root,rootl,rootr,T);
209 split(rootl,rootl,rootm,S);
210 add(rootm,z);
211 root=merge(rootl,merge(rootm,rootr));
212 return ;
213 }
214 void Invert(int x,int y){
215 top=0;
216 if(p[x].ind>p[y].ind){
217 std::swap(x,y);
218 }
219 int lca(r);
220 int tmpx(x),tmpy(y);
221 while(p[x].tp!=p[y].tp){
222 if(p[p[x].tp].dep>p[p[y].tp].dep){
223 top++;
224 ch[top].ind=p[p[x].tp].ind;
225 ch[top].len=p[x].ind-p[p[x].tp].ind+1;
226 ch[top].x=true;
227 x=p[p[x].tp].fa;
228 }else{
229 top++;
230 ch[top].ind=p[p[y].tp].ind;
231 ch[top].len=p[y].ind-p[p[y].tp].ind+1;
232 ch[top].x=false;
233 y=p[p[y].tp].fa;
234 }
235 }
236 if(p[x].dep<=p[y].dep){
237 top++;
238 ch[top].ind=p[x].ind;
239 ch[top].len=p[y].ind-p[x].ind+1;
240 ch[top].x=false;
241 }else{
242 top++;
243 ch[top].ind=p[y].ind;
244 ch[top].len=p[x].ind-p[y].ind+1;
245 ch[top].x=true;
246 }
247 std::sort(ch+1,ch+top+1,cmp);
248 int tmptop(top);
249 int root_(0);
250 while(top){
251 int S(ch[top].ind-1),T(ch[top].ind+ch[top].len-1);
252 split(root,rootl,rootr,T);
253 split(rootl,rootl,rootm,S);
254 root=merge(rootl,rootr);
255 if(ch[top].x){
256 trr(rootm);
257 }
258 root_=merge(rootm,root_);
259 top--;
260 }
261 trr(root_);
262 top=1;
263 while(top<=tmptop){
264 int S(ch[top].ind-1);
265 split(root,rootl,rootr,S);
266 split(root_,rootm,root_,ch[top].len);
267 if(ch[top].x){
268 trr(rootm);
269 }
270 root=merge(rootl,merge(rootm,rootr));
271 top++;
272 }
273 return ;
274 }
275 lnt Sum(int x,int y){
276 lnt ans(0);
277 while(p[x].tp!=p[y].tp){
278 if(p[p[x].tp].dep<p[p[y].tp].dep){
279 std::swap(x,y);
280 }
281 int S(p[p[x].tp].ind-1),T(p[x].ind);
282 split(root,rootl,rootr,T);
283 split(rootl,rootl,rootm,S);
284 ans=ans+tr[rootm].sum;
285 root=merge(rootl,merge(rootm,rootr));
286 x=p[p[x].tp].fa;
287 }
288 if(p[x].dep>p[y].dep){
289 std::swap(x,y);
290 }
291 int S(p[x].ind-1),T(p[y].ind);
292 split(root,rootl,rootr,T);
293 split(rootl,rootl,rootm,S);
294 ans=ans+tr[rootm].sum;
295 root=merge(rootl,merge(rootm,rootr));
296 return ans;
297 }
298 lnt Major(int x,int y){
299 lnt ans(-0x3f3f3f3f3f3fll);
300 while(p[x].tp!=p[y].tp){
301 if(p[p[x].tp].dep<p[p[y].tp].dep){
302 std::swap(x,y);
303 }
304 int S(p[p[x].tp].ind-1),T(p[x].ind);
305 split(root,rootl,rootr,T);
306 split(rootl,rootl,rootm,S);
307 ans=std::max(ans,tr[rootm].maxval);
308 root=merge(rootl,merge(rootm,rootr));
309 x=p[p[x].tp].fa;
310 }
311 if(p[x].dep>p[y].dep){
312 std::swap(x,y);
313 }
314 int S(p[x].ind-1),T(p[y].ind);
315 split(root,rootl,rootr,T);
316 split(rootl,rootl,rootm,S);
317 ans=std::max(ans,tr[rootm].maxval);
318 root=merge(rootl,merge(rootm,rootr));
319 return ans;
320 }
321 lnt Minor(int x,int y){
322 lnt ans(0x3f3f3f3f3f3fll);
323 while(p[x].tp!=p[y].tp){
324 if(p[p[x].tp].dep<p[p[y].tp].dep){
325 std::swap(x,y);
326 }
327 int S(p[p[x].tp].ind-1),T(p[x].ind);
328 split(root,rootl,rootr,T);
329 split(rootl,rootl,rootm,S);
330 ans=std::min(ans,tr[rootm].minval);
331 root=merge(rootl,merge(rootm,rootr));
332 x=p[p[x].tp].fa;
333 }
334 if(p[x].dep>p[y].dep){
335 std::swap(x,y);
336 }
337 int S(p[x].ind-1),T(p[y].ind);
338 split(root,rootl,rootr,T);
339 split(rootl,rootl,rootm,S);
340 ans=std::min(ans,tr[rootm].minval);
341 root=merge(rootl,merge(rootm,rootr));
342 return ans;
343 }
344 void pia(int spc){
345 if(!spc){
346 return ;
347 }
348 push_down(spc);
349 pia(lll);
350 printf("%lld ",tr[spc].val);
351 pia(rrr);
352 return ;
353 }
354 int main(){
355 scanf("%d%d%d",&n,&m,&r);
356 for(int i=1;i<=n;++i){
357 int a,b;
358 scanf("%d%d",&a,&b);
359 ade(a,b);
360 ade(b,a);
361 }
362 build(1,n,root,0);
363 Basic_dfs(r,r);
364 Build_dfs(r,r);
365 int pro(0);
366 while(m--){
367 int x,y,z;
368 scanf("%s",cmd+1);
369 if(cmd[1]=='I'){
370 if(cmd[3]=='c'){
371 scanf("%d%d%d",&x,&y,&z);
372 Increase(x,y,lnt(z));
373 }
374 if(cmd[3]=='v'){
375 scanf("%d%d",&x,&y);
376 Invert(x,y);
377 }
378 }
379 if(cmd[1]=='S'){
380 scanf("%d%d",&x,&y);
381 printf("%lld\n",Sum(x,y));
382 }
383 if(cmd[1]=='M'){
384 if(cmd[2]=='a'){
385 scanf("%d%d",&x,&y);
386 printf("%lld\n",Major(x,y));
387 }
388 if(cmd[2]=='i'){
389 scanf("%d%d",&x,&y);
390 printf("%lld\n",Minor(x,y));
391 }
392 }
393 }
394 return 0;
395 }
BZOJ3159: 决战(FHQ Treap)的更多相关文章
- fhq treap最终模板
新学习了fhq treap,厉害了 先贴个神犇的版, from memphis /* Treap[Merge,Split] by Memphis */ #include<cstdio> # ...
- NOI 2002 营业额统计 (splay or fhq treap)
Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每 ...
- 【POJ2761】【fhq treap】A Simple Problem with Integers
Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. On ...
- 【fhq Treap】bzoj1500(听说此题多码上几遍就能不惧任何平衡树题)
1500: [NOI2005]维修数列 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 15112 Solved: 4996[Submit][Statu ...
- 「FHQ Treap」学习笔记
话说天下大事,就像fhq treap —— 分久必合,合久必分 简单讲一讲.非旋treap主要依靠分裂和合并来实现操作.(递归,不维护fa不维护cnt) 合并的前提是两棵树的权值满足一边的最大的比另一 ...
- FHQ Treap摘要
原理 以随机数维护平衡,使树高期望为logn级别 不依靠旋转,只有两个核心操作merge(合并)和split(拆分) 因此可持久化 先介绍变量 ; int n; struct Node { int v ...
- FHQ Treap小结(神级数据结构!)
首先说一下, 这个东西可以搞一切bst,treap,splay所能搞的东西 pre 今天心血来潮, 想搞一搞平衡树, 先百度了一下平衡树,发现正宗的平衡树写法应该是在二叉查找树的基础上加什么左左左右右 ...
- 在平衡树的海洋中畅游(四)——FHQ Treap
Preface 关于那些比较基础的平衡树我想我之前已经介绍的已经挺多了. 但是像Treap,Splay这样的旋转平衡树码亮太大,而像替罪羊树这样的重量平衡树却没有什么实际意义. 然而类似于SBT,AV ...
- 浅谈fhq treap
一.简介 fhq treap 与一般的treap主要有3点不同 1.不用旋转 2.以merge和split为核心操作,通过它们的组合实现平衡树的所有操作 3.可以可持久化 二.核心操作 代码中val表 ...
随机推荐
- Solution -「NOI 2012」「洛谷 P2050」美食节
\(\mathcal{Description}\) Link. 美食节提供 \(n\) 种菜品,第 \(i\) 种的需求量是 \(p_i\),菜品由 \(m\) 个厨师负责制作,第 \(j\) ...
- Solution -「CF 1392G」Omkar and Pies
\(\mathcal{Description}\) Link. 给定两个长度为 \(K\) 的 \(01\) 串 \(S,T\) 和 \(n\) 组操作 \((a_i,b_i)\),意义为交换 ...
- verification 验证环境配置传递
验证环境配置传递 tc配置env 继承关系: tc_base->tc_base_bt->tc_xx base_env->xx_env base_env_cfg->xx_env_ ...
- RFC2544优化步长测试——信而泰网络测试仪实操
一.测试拓扑 拓扑说明 1.测试仪两个端口和DUT两个端口相连 2.测试仪P1端口发出流量,经过DUT转发后,从B端口发出,进入测试仪P2端口. 二.测试思路 1.在测试仪端口上创建两个Interfa ...
- 自助式BI工具怎么选?这款用过都说好!
随着大数据时代的到来,很多公司的业务数据量不断增长,公司必须集中精力管理数据,并在BI工具的帮助下进行数据分析,以便从过去的数据中获得洞察力,预测未来的发展.近年来,随着企业对数据的关注度的增加,企业 ...
- 作为报表工具,Excel移动报表的优势和劣势
Excel是应用最广泛的报表工具,它集数据存储.数据处理.数据分析于一身,广泛应用于各行各业的日常工作中(无论这个企业的信息化程度有多高.多低).而且随着Office365的普及,软件License的 ...
- 记一次阿里云oss文件上传服务假死
引言 记得以前刚开始学习web项目的时候,经常涉及到需要上传图片啥的,那时候都是把图片上传到当前项目文件夹下面,每次项目一重启图片就丢了.虽然可以通过修改/tomcat/conf/server.xml ...
- C# Task和异步方法
本文主要参考: https://www.cnblogs.com/qtiger/p/13497807.html ThreadPool中有若干数量的线程.当有任务需要处理时,会从线程池中获取一个空闲的线程 ...
- maven实现compile时将资源目录输出到target中
由于现在项目采用的是 jboot 框架,升级最新版本2.1.5后,需要将原来的webroot资源改到 src/main/webapp目录下, 发现转移后,通过框架的app.java入口main函数无法 ...
- ibv_get_device_list()函数
struct ibv_device** ibv_get_device_list(int *num_devices); 描述 函数用来返回一个当前可用的RDMA设备数组. 注意 数组以NULL结尾: R ...