传送门

解题思路:

算是补坑了,这题除了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. Solution -「洛谷 P4372」Out of Sorts P

    \(\mathcal{Description}\)   OurOJ & 洛谷 P4372(几乎一致)   设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...

  2. 原来VIM还可以这样玩

    文章目录 配置文件vimrc vim 状态栏 状态栏配置内容 状态栏常用信息 显示状态栏 终端安全色 vimrc 配置文件 推荐 vi/vim命令大全 vim参阅 配置文件vimrc 在vim文件中执 ...

  3. 多表查询思路、navicat可视化软件、python操作MySQL、SQL注入问题以及其他补充知识

    昨日内容回顾 外键字段 # 就是用来建立表与表之间的关系的字段 表关系判断 # 一对一 # 一对多 # 多对多 """通过换位思考判断""" ...

  4. Vue-从入门到第三次世界大战_1

    前言:当然世界大战是大家都不希望看到的这里是代表我会一直更新下去 ,那我为什么要这么写,没错我就是标题党. 先说下Vue介绍: 官网:https://cn.vuejs.org/ 为什么用:因为是TMD ...

  5. 数据库项目部署(nginx)

    1.在虚拟机2008server下载nginx http://nginx.org/download/nginx-1.17.10.zip 注1:此版本为window版本 linux版本 2. 解压软件至 ...

  6. nginx 配置ssl证书

    1.443端口配置 server { listen 443 ssl; server_name www.test.com; ssl_certificate /usr/local/nginx/cert/t ...

  7. MTK sensor 架构

    mtk architactureAP和scp 两部分组成从上到下的整体的结构是 app -->framerwork-->native-->hal -->kernel --> ...

  8. 手把手教你如何通过CC2531抓取Zigbee包,并解析加密Zigbee包

    前言 好久不见啊,大伙假期过得咋样? 最近我在研究 Zigbee ,使用了EFR32(购买链接)的开发板,之前也研究过一点,水了几篇文章,但是没有深了解和使用.最近 arduino 玩腻了,我开始回过 ...

  9. jmeter非gui之shell脚本

    非gui运行脚本,如果目录非空,会报不能写的错 可以通过shell脚本来处理: #!/bin/bash filename=`date +'%Y%m%d%H%M%S'` if [ -d /root/te ...

  10. oracel数据库ORA-28001: the password has expired

    调试c#项目时登录用户不成功ORA-28001: the password has expired错误 密码过期失效 网上查了一下,是Oracle11g密码过期的原因 Oracle提示错误消息ORA- ...