【GDSOI2019】滑稽二乘法【数据结构】【LCT】
Description

点数<=100000,操作数<=200000
Solution
经典的LCT维护子树路径信息的问题。
具体来说,我们对于每一个节点,它在splay上的子树对应了原树中的一条祖先后代链(换过根的),记录这个点的splay子树中的所有黑点以及它们的虚子树中的所有黑点分别到这条祖先后代链的链顶和链底的0次,1次,2次距离和,另外记录splay的子树的所有虚儿子到这条链的答案。
update相当于是合并两条链,以到链顶为例,左半边直接加,右半边每个的距离要多左子树的大小,利用\((x+v)^2=x^2+2xv+v^2\)拆开来计算即可。
同时维护到链顶和链底是为了在reverse操作的时候能够快速求出答案。
update以及access的时候0次1次2次项拆系数合并即可,可以写成模块化就简单一些。
时间复杂度\(O(n\log n)\)
Code
我也不知道为什么不开O2跑不过...
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
typedef long long LL;
const int N=100005;
const int mo=998244353;
using namespace std;
int n;
LL sqr(const LL x) {return x*x;}
namespace LCT
{
int fn[N],f[N],t[N][2],r[N];
LL sz[N],vl[N][3],sp[N],sm[N][2][3];
LL cl[N];
void rev(const int k)
{
r[k]^=1,swap(sm[k][0],sm[k][1]);
}
void down(int k)
{
if(r[k])
{
swap(t[k][0],t[k][1]),fn[t[k][0]]=0,fn[t[k][1]]=1;
rev(t[k][0]),rev(t[k][1]);
r[k]=0;
}
}
void merge(LL *a,LL *b,const LL u,const LL v)
{
a[0]=a[0]+v*b[0];
a[1]=a[1]+v*(b[1]+b[0]*u);
a[2]=a[2]+v*(b[2]+b[1]*u*(LL)2+b[0]*sqr(u));
}
void up(int k)
{
if(!k) return;
sz[k]=sz[t[k][0]]+sz[t[k][1]]+1;
sp[k]=sp[t[k][0]]+vl[k][2]+sp[t[k][1]];
fo(x,0,1)
{
int u=t[k][x],v=t[k][1^x];
sm[k][x][0]=cl[k],sm[k][x][1]=sz[u]*cl[k],sm[k][x][2]=sqr(sz[u])*cl[k];
merge(sm[k][x],sm[u][x],0,1);
merge(sm[k][x],vl[k],sz[u],1);
merge(sm[k][x],sm[v][x],sz[u]+1,1);
}
}
void hb(int x,int y,int p)
{
if(x&&p>=0) t[x][p]=y;
if(y) fn[y]=p,f[y]=x;
}
void rot(int k)
{
int fa=f[k],p=fn[k];
hb(fa,t[k][1-p],p);
hb(f[fa],k,fn[fa]);
hb(k,fa,1-p);
up(fa),up(k),up(f[k]);
}
int d[N];
void splay(int k,int x)
{
d[d[0]=1]=k;
while(fn[d[d[0]]]!=-1&&f[d[d[0]]]!=x) d[++d[0]]=f[d[d[0]-1]];
fod(i,d[0],1) down(d[i]);
while(f[k]!=x&&fn[k]!=-1)
{
if(fn[f[k]]==-1||f[f[k]]==x) rot(k);
else if(fn[k]==fn[f[k]]) rot(f[k]),rot(k);
else rot(k),rot(k);
}
}
void access(int k)
{
int r=k;
splay(k,0);
merge(vl[k],sm[t[k][1]][0],1,1),hb(k,t[k][1],-1),t[k][1]=0;
up(k);
while(f[k])
{
int x=f[k];splay(x,0);
merge(vl[x],sm[t[x][1]][0],1,1);
merge(vl[x],sm[k][0],1,-1);
fn[t[x][1]]=-1,hb(x,k,1),up(x),k=x;
}
splay(r,0);
}
void make(int k)
{
access(k),rev(k);
}
void link(int x,int y)
{
make(y),access(x);
f[y]=x,fn[y]=-1;
up(x);
}
void init()
{
fo(i,1,n) sz[i]=1;
fo(i,1,n-1)
{
int x,y;
scanf("%d%d",&x,&y);
link(x,y);
}
}
void modify(int k)
{
make(k),cl[k]^=1,up(k);
}
LL query(int x,int y)
{
make(x),access(y);
return sp[y];
}
}
using namespace LCT;
int main()
{
cin>>n;
init();
int q;
cin>>q;
fo(i,1,q)
{
int tp,x,y;
scanf("%d%d",&tp,&x);
if(tp==0) modify(x);
else
{
scanf("%d",&y);
printf("%lld\n",query(x,y)%mo);
}
}
}
【GDSOI2019】滑稽二乘法【数据结构】【LCT】的更多相关文章
- 模板—数据结构—LCT
模板—数据结构—LCT Code: #include <cstdio> #include <algorithm> using namespace std; #define N ...
- 树上数据结构——LCT
目录 树上数据结构--LCT 概述 基本概念 核心操作 其他操作 完整模板 树上数据结构--LCT 概述 LCT是一种强力的树上数据结构,支持以下操作: 链上求和 链上求最值 链上修改 子树修改 子树 ...
- Redis系统学习 二、数据结构
一.字符串 1.在Redis里,字符串是最基本的数据结构.当你在思索着关键字-值对时,你就是在死锁着字符串数据结构.不要被名字给搞混了. 常见实例: set users:leto " ...
- 剑指offer-第二章数据结构(数组,字符串,链表,树,栈与队列)及例题
一.数组(最简单的数据结构) 定义:占据一块连续内存并按照顺序存储数据.创建时先指定大小,分配内存. 优点:时间效率高.实现简单的hash(下标为key,对应的数据为value) 缺点:空间效率差.如 ...
- mysql索引之二:数据结构及算法原理
摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...
- Redis(二)数据结构与键管理
一.基础知识 1.全局命令 keys * :查看所有键 dbsize:返回当前数据库中键的总数 exists key:检查键是否存在 del key ... :删除键 expire key sec ...
- 二.python数据结构的性能分析
目录: 1.引言 2.列表 3.字典 一.引言 - 现在大家对 大O 算法和不同函数之间的差异有了了解.本节的目标是告诉你 Python 列表和字典操作的 大O 性能.然后我们将做一些基于时间的实验来 ...
- linux内核系列(二)内核数据结构之链表
双向链表 传统链表与linu内核链表的区别图: 图一 图二 从上图中看出在传统链表中各种不同链表间没有通用性,因为各个数据域不同,而在linux内核中巧妙将链表结构内嵌到数据域结构中使得不同结构之间能 ...
- ES6快速入门(二)数据结构
ES6快速入门 一.解构 1. 对象解构 let person = { name: 'Tang', age: 28 }; //必须同名,必须初始化 let {name, age} = person; ...
随机推荐
- CSP 最大的矩形(201312-3)
问题描述 在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ i ≤ n)个矩形的高度是hi.这n个矩形构成了一个直方图.例如,下图中六个矩形的高度就分别是3, 1, 6, 5, 2, 3 ...
- 调用webService学习小结
这段时间项目进行到了最后时刻,但是还有很多需求没有搞清楚,眼看deadline越来越近,压力也越来越大.现在我的主要工作是将别人开发好的一个系统给加载到我们系统中,使用的方法是通过webService ...
- Centos7环境下Docker容器的安装与卸载
Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机).bare metal. ...
- 帝国cms 通过tags给产品或者新闻进行分类
1.增加TAGS分类 先找到栏目== >TAGS管理 == > 管理TAGS分类 == >增加分类 2.增加相关的tag标签,也要选好TAGS分类 3.增加自定义标签模板 具体怎么写 ...
- 使用CSS设置背景图片,图片比较大,完全显示在一个DIV中
做的时候想要边框为比较好看的样式,需要UI切图并且放在div中,看起来会好看点 像这样的,我随便挑选了一个,UI帮我切图出来 需要把这个图片填到相应的div里面,但是很显然碰到一个问题,图片太大,而且 ...
- 仿造email后缀自动添加功能(1)
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- python、第七篇:ORM框架SQLAlchemy
一 介绍 SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取 ...
- verilog 实现DDS
一.DDS的原理 直接数字频率合成器(DDS),功能是通过输入频率输入字从而实现改变输出信号的频率的功能,它所利用的原理就是虽然对于一段正弦信号来说其幅度值是非线性的,但是其相位的值却是线性增加的,如 ...
- Linux :file、which 、whereis、locate、find
1 file 观察文件类型 file 文件 2 which 寻找文件 选项与参数: -a : 将所有由PATH目录中可以知道的指令列出,而不止一个被找到的指令名称 3 whereis 寻找特定文件 ...
- CUDA, CUDNN 版本查询
CUDA 查询: cat /usr/local/cuda/version.txt 或者 nvcc -V (也可以看到版本信息) CUDNN 查询 cat /usr/local/cuda/include ...