传送门

解题思路:

算是补坑了,这题除了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)的更多相关文章

  1. fhq treap最终模板

    新学习了fhq treap,厉害了 先贴个神犇的版, from memphis /* Treap[Merge,Split] by Memphis */ #include<cstdio> # ...

  2. NOI 2002 营业额统计 (splay or fhq treap)

    Description 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每 ...

  3. 【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 ...

  4. 【fhq Treap】bzoj1500(听说此题多码上几遍就能不惧任何平衡树题)

    1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 15112  Solved: 4996[Submit][Statu ...

  5. 「FHQ Treap」学习笔记

    话说天下大事,就像fhq treap —— 分久必合,合久必分 简单讲一讲.非旋treap主要依靠分裂和合并来实现操作.(递归,不维护fa不维护cnt) 合并的前提是两棵树的权值满足一边的最大的比另一 ...

  6. FHQ Treap摘要

    原理 以随机数维护平衡,使树高期望为logn级别 不依靠旋转,只有两个核心操作merge(合并)和split(拆分) 因此可持久化 先介绍变量 ; int n; struct Node { int v ...

  7. FHQ Treap小结(神级数据结构!)

    首先说一下, 这个东西可以搞一切bst,treap,splay所能搞的东西 pre 今天心血来潮, 想搞一搞平衡树, 先百度了一下平衡树,发现正宗的平衡树写法应该是在二叉查找树的基础上加什么左左左右右 ...

  8. 在平衡树的海洋中畅游(四)——FHQ Treap

    Preface 关于那些比较基础的平衡树我想我之前已经介绍的已经挺多了. 但是像Treap,Splay这样的旋转平衡树码亮太大,而像替罪羊树这样的重量平衡树却没有什么实际意义. 然而类似于SBT,AV ...

  9. 浅谈fhq treap

    一.简介 fhq treap 与一般的treap主要有3点不同 1.不用旋转 2.以merge和split为核心操作,通过它们的组合实现平衡树的所有操作 3.可以可持久化 二.核心操作 代码中val表 ...

随机推荐

  1. SQL注入蠕虫分析//未完待续

    蠕虫代码: DECLARE @S VARCHAR(4000);SET @S=CAST(0x4445434C415245204054205641524348415228323535292C4043205 ...

  2. Spring AOP基础概念及自定义注解式AOP初体验

    对AOP的理解开始是抽象的,看到切点的匹配方式其实与正则表达式性质大致一样就基本了解AOP是基本是个什么作用了.只是整个概念更抽象,需要具化理解.下图列表是AOP相关概念解释,可能也比较抽象^_^ 比 ...

  3. Spring Boot部署之 web项目war包运行

    传统的部署方式:将项目打成war包,放入tomcat 的webapps目录下面,启动tomcat,即可访问. 具体打war包流程: 1.pom.xml配置文件修改: 2.改造启动类,如果是war包发布 ...

  4. k8s家族Pod辅助小能手Init容器认知答疑?

    k8s家族Pod辅助小能手Init容器认知答疑? k8s集群Init 容器是一种特殊容器,职责是在Pod的生命周期中作为应用容器的前置启动容器. 在很多应用场景中,在 Pod 内的应用容器正式启动之前 ...

  5. [办公软件]Mac安装office 2019官方原版安装包并激活

    office 2019介绍 Office 2019 mac简体中文版已经推出,具体包含Word, Excel, PowerPoint, Outlook, OneNote五大套件,注册登陆用户可以漫游文 ...

  6. Windows server 2012安装vm-tools遇到的问题

    Windows server 2012安装VM tools异常解决办法 在VMWare虚拟机上安装Windows Server 2012之 后安装VMWare Tools时报如下错误信息: 问题:缺少 ...

  7. 解决shell脚本错误$’r’ command not found

    从windows上传了一个脚本到Linux上执行 出现如下错误:$'\r': command not found这是windows与Unix文本编辑的默认格式不同造成的,需要转成unix格式. 解决方 ...

  8. 【C# 线程】线程池 ThreadPool

    Overview    如今的应用程序越来越复杂,我们常常需要使用<异步编程:线程概述及使用>中提到的多线程技术来提高应用程序的响应速度.这时我们频繁的创建和销毁线程来让应用程序快速响应操 ...

  9. 小白学python第1问: int 占几个字节?

    windows 64位机器,python3.7:后面的文章中,没有特别说明的话,都是在该环境下运行 int 占几个字节? C语言中(GCC编译器),int 占据4个字节,python呢? 我们用pyt ...

  10. startActivityForResult跳转后回调数据

    从AActivity向BActivity跳转后,关闭BActivity并向AActivity回调一些数据: 建立AActivity.java文件: 1 public class AActivity e ...