实际上去掉主函数不长于线段树 3。

对于 LCT 每个点的虚儿子。用 splay 把它们串起来(称为新 splay,虽然是共用的)。

具体来说,设 \(1\le x\le n\) 是原 LCT 的 splay 的根,\(x+n\) 就用来挂载其子树信息(虚实都包括),认 \(x+n\) 做父亲。

而每个有虚儿子的结点 \(x\) 具有 splay 上儿子 \(n<rt_x\le 2n\) 作为新 splay 的一个根来记录其虚儿子子树信息,这个 \(rt_x\) 所在的新 splay 上就有的是它下面虚儿子的 \(y+n\)。

每个点维护的信息包括虚子树信息和和实 splay 信息,以及虚实的标记,当然 \(n+1\sim 2n\) 的范围没有虚儿子(也没有虚标记),虚标记传到 \(rt_x\) 的时候也要变成实标记。

虚子树信息需要一道累加上实子树信息。这样就可以写出链、子树修改查询的代码了:

node query(int x,int y){split(x,y);return sr[y];}
node query(int x){split(crt,x);return v[x]+sr[rt[x]];}
void modify(int x,int y,tag t){split(x,y);ADD(y,t,tag());}
void modify(int x,tag t){split(crt,x);ADD(rt[x],t,tag());v[x]=v[x]*t;pushup(x);}

其中 sr 是实信息和,sv 是虚信息和。

至于换根的操作,直接 makeroot 即可。而换儿子只需找到父亲 linkcut 即可。

还有问题:splay 的时候会改变当前 splay 根,因此还需支持新 splay 的添加/删除虚子树。添加很简单,挂成新的根就可以。删除只需找到前驱拼上右儿子即可。splay 前/后需要删除/重新添加这个子树的信息。

access 也涉及改变虚儿子状态,也要类似的删除/添加。

还有一个调了一个下午(这个调试真的麻烦)的问题是 link 和一般 LCT 有所不同。link(x,y) 需要先 access,splay(y) 因为插入虚儿子有更新信息环节。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
const int maxn=4e5+5,INF=1e12;
struct tag{
int k,b;
tag(int x=1,int y=0){k=x,b=y;}
}rtag[maxn],vtag[maxn];
struct node{
int mn,mx,sze,sum;
node(int x=INF,int y=-INF,int z=0,int w=0){mn=x,mx=y,sze=z,sum=w;}
}v[maxn],sr[maxn],sv[maxn];
int tg[maxn],ch[maxn][2],fa[maxn],a[maxn],st[maxn],tp=0,sze[maxn],rt[maxn],n,q;
tag operator ^(tag A,tag B){return {B.k*A.k,B.k*A.b+B.b};}
node operator *(node A,tag B){
if(!A.sze)return {INF,-INF,0,0};
return {B.k*A.mn+B.b,B.k*A.mx+B.b,A.sze,B.k*A.sum+B.b*A.sze};
}
node operator +(node A,node B){return {min(A.mn,B.mn),max(A.mx,B.mx),A.sze+B.sze,A.sum+B.sum};}
#define ls(x) (ch[x][0])
#define rs(x) (ch[x][1])
int nroot(int x){return ls(fa[x])==x||rs(fa[x])==x;}
int whs(int x){return rs(fa[x])==x;}
void pushup(int x){
if(x>n){
v[x]=sr[x-n]+sv[x-n];
sr[x]=v[x]+sr[ls(x)]+sr[rs(x)];
}else{
sr[x]=v[x]+sr[ls(x)]+sr[rs(x)];
sv[x]=sr[rt[x]]+sv[ls(x)]+sv[rs(x)];
pushup(x+n);
}
}
void rot(int x){
int y=fa[x],z=fa[y],k=whs(x),w=ch[x][k^1];
if(nroot(y))ch[z][whs(y)]=x;fa[y]=x,fa[x]=z;
ch[y][k]=w;if(w)fa[w]=y;ch[x][k^1]=y;
pushup(y),pushup(x);
}
void ADD(int x,tag tr,tag tv){
if(!x)return ;
v[x]=v[x]*tr,sr[x]=sr[x]*tr,rtag[x]=rtag[x]^tr;
sv[x]=sv[x]*tv,vtag[x]=vtag[x]^tv;
}
void FLIP(int x){swap(ls(x),rs(x)),tg[x]^=1;}
void pushdown(int x){
if(tg[x])FLIP(ls(x)),FLIP(rs(x)),tg[x]=0;
if(x>n){
ADD(ls(x),rtag[x],tag());
ADD(rs(x),rtag[x],tag());
ADD(x-n,rtag[x],rtag[x]);
rtag[x]=tag();
}else{
ADD(ls(x),rtag[x],vtag[x]);
ADD(rs(x),rtag[x],vtag[x]);
ADD(rt[x],vtag[x],tag());
rtag[x]=tag(),vtag[x]=tag();
}
}
void del(int x,int y);
void ins(int x,int y);
void splay(int x);
void ins(int x,int y){
if(y<=n)return ;
if(!rt[x])pushup(y),rt[x]=y,pushup(x);
else{
int p=rt[x];
ls(y)=p,fa[p]=y,rt[x]=y;
pushup(y);pushup(x);
}
}
void del(int x,int y){
if(y<=n)return ;
splay(y),fa[ls(y)]=fa[rs(y)]=0;
if(ls(y)){
int p=ls(y);while(rs(p))pushdown(p),p=rs(p);
splay(p);rs(p)=rs(y),fa[rs(y)]=p;
pushup(p),rt[x]=p;
}else rt[x]=rs(y);
ls(y)=rs(y)=0;
pushup(y),pushup(x);
}
void splay(int x){
int y=x;while(nroot(y))y=fa[y];
if(y<=n&&fa[y])del(fa[y],y+n);
y=x;st[tp=1]=y;while(nroot(y))y=fa[y],st[++tp]=y;
while(tp)pushdown(st[tp--]);
while(nroot(x)){
int y=fa[x];
if(nroot(y))rot(whs(y)==whs(x)?y:x);
rot(x);
}
if(x<=n&&fa[x])ins(fa[x],x+n);
}
int crt,mkc=0;
void access(int x){for(int y=0;x;y=x,x=fa[x])splay(x),del(x,y+n),ins(x,rs(x)+n),rs(x)=y,pushup(x);}
void makeroot(int x){access(x),splay(x),FLIP(x);}
void split(int x,int y){
makeroot(x);
access(y);splay(y);
}
void link(int x,int y){
if(!mkc)makeroot(x);
access(y),splay(y);
fa[x]=y;
ins(y,x+n);
}
void cut(int x,int y){split(x,y);fa[x]=ch[y][0]=0;pushup(y);pushup(x);}
int findroot(int x){access(x),splay(x);while(ls(x))pushdown(x),x=ls(x);splay(x);return x;}
void cgf(int x,int y){
split(crt,x);
int f=ls(x);
if(!f)return ;
while(rs(f))pushdown(f),f=rs(f);
cut(x,f);
split(x,y);
if(findroot(y)==x)link(x,f);
else link(x,y);
}
int U[maxn],V[maxn];
node query(int x,int y){split(x,y);return sr[y];}
node query(int x){
split(crt,x);
return v[x]+sr[rt[x]];
}
void modify(int x,int y,tag t){split(x,y);ADD(y,t,tag());}
void modify(int x,tag t){split(crt,x);ADD(rt[x],t,tag());v[x]=v[x]*t;pushup(x);}
int currt(int x){x=findroot(x);if(!fa[x])return x;return currt(fa[x]);}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>q;for(int i=1;i<n;i++)cin>>U[i]>>V[i];
for(int i=1,x;i<=n;i++)cin>>x,v[i]={x,x,1,x},pushup(i);cin>>crt;
for(int i=1;i<n;i++)link(U[i],V[i]);
for(int i=1;i<=q;i++){
int tp,x,y,z;
cin>>tp>>x;
if(tp==0)cin>>y,modify(x,{0,y});
if(tp==1)crt=x;
if(tp==2)cin>>y>>z,modify(x,y,{0,z});
if(tp==3)cout<<query(x).mn<<endl;
if(tp==4)cout<<query(x).mx<<endl;
if(tp==5)cin>>y,modify(x,{1,y});
if(tp==6)cin>>y>>z,modify(x,y,{1,z});
if(tp==7)cin>>y,cout<<query(x,y).mn<<endl;
if(tp==8)cin>>y,cout<<query(x,y).mx<<endl;
if(tp==9)cin>>y,cgf(x,y);
if(tp==10)cin>>y,cout<<query(x,y).sum<<endl;
if(tp==11)cout<<query(x).sum<<endl;
}
return 0;
}

AAAT 笔记(P5649)的更多相关文章

  1. git-简单流程(学习笔记)

    这是阅读廖雪峰的官方网站的笔记,用于自己以后回看 1.进入项目文件夹 初始化一个Git仓库,使用git init命令. 添加文件到Git仓库,分两步: 第一步,使用命令git add <file ...

  2. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  3. SQL Server技术内幕笔记合集

    SQL Server技术内幕笔记合集 发这一篇文章主要是方便大家找到我的笔记入口,方便大家o(∩_∩)o Microsoft SQL Server 6.5 技术内幕 笔记http://www.cnbl ...

  4. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  5. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  6. NET Core-学习笔记(三)

    这里将要和大家分享的是学习总结第三篇:首先感慨一下这周跟随netcore官网学习是遇到的一些问题: a.官网的英文版教程使用的部分nuget包和我当时安装的最新包版本不一致,所以没法按照教材上给出的列 ...

  7. springMVC学习笔记--知识点总结1

    以下是学习springmvc框架时的笔记整理: 结果跳转方式 1.设置ModelAndView,根据view的名称,和视图渲染器跳转到指定的页面. 比如jsp的视图渲染器是如下配置的: <!-- ...

  8. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  9. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  10. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

随机推荐

  1. Python消息队列之Huey

    缘起: 之前在Python中使用最多的就是Celery, 同样的在这次项目中使用了Celery+eventlet的方式,但是由于具体执行的逻辑是使用的异步编写的, 当时就出现了一个问题,当使用http ...

  2. MySQL 8.0 为什么会放弃查询缓存?

    什么是查询缓存? 查询缓存就是将一次查询结果存储在内存中,假如下一次查询结果在内存中,就直接在内存中读取. 设计初衷 当然是提高性能,通过缓存来减少解析器.优化器.存储引擎的执行时间. MySQL查询 ...

  3. ZCMU-1051

    比较来说不太难其实,当然找到一定的公式这与前面的1033相识,都会用到f(i,j)=f(i-1,j)+f(i-1,j-1) 我们可以先从小部分看出来,一层可以整体或者两部分,在面对第i层看前面i-1层 ...

  4. HTML5 拖拽接口

    1.首先,为了使元素可拖动,要先设置元素为可拖拽 方法:添加draggable属性,设置为 true 注意:链接和图像默认就支持拖拽,另外,如果一个元素中的文本被选中,那么这个元素和他的文本节点此时都 ...

  5. 树莓派获取唯一ID

    树莓派的CPU有序列号,可以通过读取 /proc/cpuinfo 获取 储存的UUID,可以通过 ls /dev/disk/by-uuid或blkid

  6. 【矩阵压缩】codeforces 1980 E. Permutation of Rows and Columns

    题目链接 https://codeforces.com/problemset/problem/1980/E 题意 共输入\(T\)组测试用例,每组测试用例第一行输入两个整数\(n, m\),分别代表输 ...

  7. ESP32网页示波器+波形发生器

    项目开源地址:https://github.com/guohaomeng/ESP32WebScope ESP32WebScope 只用一块ESP32制作的ESP32网页示波器+波形发生器,可以拿来生成 ...

  8. TS 原理详细解读(7)绑定1-符号

    在上一节主要介绍了语法树的解析生成.就好比电脑已经听到了"你真聪明"这句话,现在要让电脑开始思考这句话的含义--是真聪明还是假聪明. 这是一个非常的复杂的过程,接下来将有连续几节内 ...

  9. Linux 查看 && 修改端口范围限制

    1.显示当前临时端口的范围: sysctl net.ipv4.ip_local_port_range或 cat /proc/sys/net/ipv4/ip_local_port_range一般情形下: ...

  10. Qt/C++编写全能播放组件(支持ffmpeg2/3/4/5/6/Qt4/5/6)

    一.前言 从代码层面以及自由度来说,用ffmpeg来写全能播放组件是最佳方案(跨平台最好最多.编解码能力最强),尽管已经有优秀的vlc/mpv等方案可以直接用,但是vlc/mpv对标主要是播放器应用层 ...