[科技] 假装是ETT的ETT

[科技] 假装是ETT的ETT

Codechef 的 April Challenge 2019 Division 1 的 Sonya and Queries 这题的\(45\)分部分分,似乎是一个出栈入栈序\(ETT\),看着似乎还挺好的,就写了写。那么这里就讲一讲这个假装是\(ETT\)的\(ETT\)。

\(ETT\),全称\(Euler-Tour-Tree\)。实际上真实的\(ETT\)是用树上的欧拉回路来写的,但是也有这种省略欧拉回路为入栈出栈序列的\(ETT\),个人感觉可能后者更容易实现,但是与前者的不同就是似乎后者不能换根,但是可以进行链上操作……如果要学欧拉回路的\(ETT\)的话可以看这个文章。

首先出栈入栈序列,或者叫做括号序这个东西,用处还是挺多的,比较常见的就是用在\(RMQ\ LCA\)的问题上,可以做到\(O(nlogn)\)预处理,\(O(1)\)查询\(LCA\)的优秀复杂度。其主要的性质就是对于每一个点的出栈与入栈时间\(in[x]\)和\(out[x]\),都有\([in[x], out[x]]\)中所有的节点都是\(x\)的子树中的节点。这个还是比较显然的,这也是\(ETT\)能够在某些地方代替\(LCT\)维护动态树的基础。

于是我们尝试用括号序\(ETT\)实现一些\(LCT\)的操作。

首先是最基础的\(Link / Cut\):

考虑到\(Link / Cut\)就是把\(x\)的子树和\(x\)的父亲断开或者接到另一个节点\(y\)上,而这个操作在括号序上的表现即是序列上一个连续段的平移。这个操作我们再熟悉不过了,利用平衡树就可以优秀地解决了。

然后是一些基础的子树操作,例如子树加,子树赋值,子树求和,子树求\(Max\)等等:

还是考虑括号序的性质,\(x\)的子树都在\([in[x], out[x]]\)这个区间中,在平衡树中将这个区间分裂出来之后找到根节点,就可以得到区间的信息了,或者打一些子树的标记了。不过需要注意的是,在子树求和的时候,由于区间中的数实际上有\(2 * sz\)个,所以答案应该要除以\(2\)。

还有一写单点的操作也是和子树操作类似的,就不赘述了。但是有一个细节也是和子树求和差不多的,就是单点操作的时候要操作两个点,这点不要忘记。

然后是一些链上的操作:

(注:这里的链上操作,博主似乎都只会那种直接到根节点的操作,并且这种方法似乎不能求链上\(\min, \max\),如果有什么更为优秀的实现方式,欢迎评论)
考虑括号序的实质是入栈出栈序列,假设我们需要操作是\(x\)到根的一条链,那么我们考虑\([1, out[x]]\)这个区间,如果对于一个节点\(u\),\(in[u]\)和\(out[u]\)都在这个区间里的话,那么说明这个节点\(u\)并不在需要操作的链上。
以链求和为例,我们就可以在平衡树插入的节点进行一些修改。对于节点\(x\),我们在\(in[x]\)出插入\(val[x]\),在\(out[x]\)出插入\(-val[x]\)。那么链求和就是\([1, out[x]]\)中的所有节点的和,这个平衡树也是可以优秀的解决的。唯一不怎么优秀的就是需要开两个平衡树……

这些大概就是一些\(ETT\)能够满足的操作了。可能博主学的并不精,勿喷……

给一道例题吧:例题
代码应该还好写的,就不放出来了……

至于Codechef么……emm……反正比赛也快结束了……\(45\)分的部分分也应该没什么人要的样子啊,我就直接放出来了吧嘿嘿嘿……反正没多少人看……

Code:

用的是\(fhq \ Treap\)来实现的……

大致就是需要支持:\(Link / Cut\)(保证操作的为原树上的边),子树求和,子树赋值,单点加,单点查询,子树加。
还算好写吧……

#include <bits/stdc++.h>
using namespace std;
const int N = 3E5 + 50;
typedef long long ll;
typedef pair<int, int> P;
typedef vector<int> Vec;
#define fi first
#define se second
#define mk make_pairint n, m, ID, clck;
struct edge {int u, v;
}E[N << 2];
ll a[N];
Vec G[N], t;
int in[N], out[N];
char s[N];namespace Treap {struct node {int ls, rs, sz, zero, fa;ll v, sum, Rnd, tag;}t[N << 1];int tot, rt;
#define ls(o) t[o].ls
#define rs(o) t[o].rs
#define pa(o) t[o].faint Newnode(ll V) {t[++tot].ls = t[tot].rs = t[tot].zero = t[tot].fa = t[tot].tag = 0; t[tot].sz = 1;t[tot].Rnd = 1ll * rand() * rand(); t[tot].sum = t[tot].v = V;return tot;}void Update(int o) {t[o].sz = 1; t[o].sum = t[o].v;t[o].sz += ( ls(o) ? t[ls(o)].sz : 0 ) + ( rs(o) ? t[rs(o)].sz : 0 );t[o].sum += ( ls(o) ? t[ls(o)].sum : 0) + ( rs(o) ? t[rs(o)].sum : 0 );}void Apply1(int o) { t[o].sum = t[o].v = 0; t[o].zero = 1; t[o].tag = 0; }void Apply2(int o, ll V) { t[o].sum += t[o].sz * V; t[o].v += V; t[o].tag += V; }void Push(int o) {if(t[o].zero) {if(ls(o)) Apply1(ls(o));if(rs(o)) Apply1(rs(o));t[o].zero = 0;}if(t[o].tag) {if(ls(o)) Apply2(ls(o), t[o].tag);if(rs(o)) Apply2(rs(o), t[o].tag);t[o].tag = 0;}}int Merge(int x, int y) {if(!x || !y) return x | y;Push(x); Push(y);if(t[x].Rnd < t[y].Rnd) {int k = Merge(t[x].rs, y);t[k].fa = x;t[x].rs = k;Update(x);return x;}else {int k = Merge(x, t[y].ls);t[k].fa = y;t[y].ls = k;Update(y);return y;}}P Split(int o, int k) {if(!o) return mk(0, 0);Push(o);if(t[ls(o)].sz == k) {int Ls = ls(o);ls(o) = 0; t[Ls].fa = 0;Update(o);return mk(Ls, o);}if(t[ls(o)].sz + 1 == k) {int Rs = rs(o);rs(o) = 0; t[Rs].fa = 0;Update(o);return mk(o, Rs);}if(t[ls(o)].sz < k) {P tmp = Split(rs(o), k - t[ls(o)].sz - 1);int Rs = t[o].rs; t[Rs].fa = 0;t[o].rs = tmp.fi;t[tmp.fi].fa = o;Update(o);return mk(o, tmp.se);}P tmp = Split(ls(o), k);int Ls = t[o].ls; t[Ls].fa = 0;t[o].ls = tmp.se;t[tmp.se].fa = o;Update(o);return mk(tmp.fi, o);}P Findroot(int o) {int las = 0, Rnk = ls(o) ? t[ls(o)].sz : 0;while(pa(o)) {if(rs(pa(o)) == o) Rnk += t[ls(pa(o))].sz + 1;o = pa(o);}return mk(o, Rnk);}void Insert(ll V) {int o = Newnode(V);rt = Merge(rt, o);}void Cut(int x, int y) {int L1 = in[x], R1 = out[x], L2 = in[y], R2 = out[y];if(L1 <= L2 && R2 <= R1) swap(x, y), swap(L1, L2), swap(R1, R2);P L = Findroot(L1), R = Findroot(R1);P tmp1 = Split(L.fi, R.se + 1);P tmp2 = Split(tmp1.fi, L.se);Merge(tmp2.fi, tmp1.se);}void Link(int x, int y) {int L1 = in[x], R1 = out[x], L2 = in[y], R2 = out[y];if(L1 <= L2 && R2 <= R1) swap(x, y), swap(L1, L2), swap(R1, R2);int o = Findroot(L1).fi;P R = Findroot(R2);P tmp1 = Split(R.fi, R.se + 1);P tmp2 = Split(tmp1.fi, R.se);int p = Merge(tmp2.fi, o);int k = Merge(p, tmp2.se);Merge(k, tmp1.se);}
}void Dfs(int o, int fa) {in[o] = ++clck; t.push_back(o);for(int i = 0; i < (int)G[o].size(); i++) {int to = G[o][i];if(to == fa) continue;Dfs(to, o);}out[o] = ++clck; t.push_back(o);
}int main() {Treap::rt = Treap::tot = 0;scanf("%d%d%d", &ID, &n, &m);if(ID == 4 || ID == 5) return puts("nmdwsm"), 0;for(int i = 1, u, v; i < n; i++) {scanf("%d%d", &u, &v);E[i] = (edge) { u, v };G[u].push_back(v); G[v].push_back(u);}scanf("%s", s + 1);for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);Dfs(1, 1);for(int i = 0; i < (int)t.size(); i++) Treap::Insert(a[t[i]]);for(int i = 1; i < n; i++) {if(s[i] == '0') continue;Treap::Cut(E[i].u, E[i].v);}while(m--) {int tp;scanf("%d", &tp);if(tp == 1) {int x;scanf("%d", &x);if(s[x] == '0') s[x] = '1', Treap::Cut(E[x].u, E[x].v);else s[x] = '0', Treap::Link(E[x].u, E[x].v);}else if(tp == 2) {int x; ll y;scanf("%d%lld", &x, &y);P p = Treap::Findroot(in[x]);Treap::Apply2(p.fi, y);}else if(tp == 3) {int x;scanf("%d", &x);P p = Treap::Findroot(in[x]);ll Sum = Treap::t[p.fi].sum;Sum >>= 1;Treap::Apply1(p.fi);P tmp1 = Treap::Split(p.fi, p.se + 1);P tmp2 = Treap::Split(tmp1.fi, p.se);Treap::t[tmp2.se].sum = Treap::t[tmp2.se].v = Sum;Treap::Merge(Treap::Merge(tmp2.fi, tmp2.se), tmp1.se);p = Treap::Findroot(out[x]);tmp1 = Treap::Split(p.fi, p.se + 1);tmp2 = Treap::Split(tmp1.fi, p.se);Treap::t[tmp2.se].sum = Treap::t[tmp2.se].v = Sum;Treap::Merge(Treap::Merge(tmp2.fi, tmp2.se), tmp1.se);}else if(tp == 4) {int x;scanf("%d", &x);P p = Treap::Findroot(in[x]);P tmp1 = Treap::Split(p.fi, p.se + 1);P tmp2 = Treap::Split(tmp1.fi, p.se);ll ans = Treap::t[tmp2.se].v;printf("%lld\n", ans);Treap::Merge(Treap::Merge(tmp2.fi, tmp2.se), tmp1.se);}else if(tp == 5) {int x;scanf("%d", &x);P p = Treap::Findroot(in[x]);ll ans = Treap::t[p.fi].sum;ans >>= 1;printf("%lld\n", ans);}else if(tp == 6) {int x;scanf("%d", &x);P p = Treap::Findroot(in[x]);Treap::Apply1(p.fi);}}return 0;
}

转载于:https://www.cnblogs.com/Apocrypha/p/10701713.html

[科技] 假装是ETT的ETT相关推荐

  1. wireshark C插件开发

    1. Wireshark对C插件的支持 每个解析器解码自己的协议部分, 然后把封装协议的解码传递给后续协议. 因此它可能总是从一个Frame解析器开始, Frame解析器解析捕获文件自己的数据包细节( ...

  2. wireshark协议解析器原理与插件编写

    工作原理 每个解析器解码自己的协议部分, 然后把封装协议的解码传递给后续协议. 因此它可能总是从一个Frame解析器开始, Frame解析器解析捕获文件自己的数据包细节(如:时间戳), 将数据交给一个 ...

  3. 7.1 useradd:创建用户

    7.1 useradd:创建用户 1 使用useradd 常规添加用户工作原理流程 在使用useradd命令时,若不加任何参数选项,后面直接跟所添加的用户名,那么系统首先会读取/etc/login.d ...

  4. 如何在C#中将 加载、编辑WPS表格?国产控件就能搞定

    Spire.XLS for .NET 是一款专业的 .NET Excel 组件, 它可以用在各种.NET 框架中,包括 .NET Core.ASP.NET 和 Windows Forms 等相关的.N ...

  5. wireshark插件 - 添加UI子树, 向子树上添加分析后的文本

    前言 要想用wireshark 插件做一个最简单的协议分析(不挎包),除了分析协议数据(纯C, 和wireshark无关),还要将分析的结果显示在wireshark树区和数据区, 只要能在树区添加子树 ...

  6. Linux 用户管理及用户权限设置

    Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统.用户的账号一方面可以帮助系统管理员对使用系统的用户进行 ...

  7. wireshark插件开发详细流程(含源码)

    亲自试了一下的用户态发包程序和wireshark插件程序.验证了其是可行的.要注意的一个问题是注意版本匹配. 这个是在应用层抓包并分析. 原文地址:http://www.cnblogs.com/Lit ...

  8. wireshark官方文档第 9 章数据包解析

    第 9 章数据包解析 9.1. 数据包解析的工作原理 对于一个已封装好的协议包,每个解析器(dissector)对其负责的一部分协议进行解码,然后将解码过程交给后续的解析器. 每个解析都从帧(Fram ...

  9. 频道信息[置顶] MPEG-2 数字视频技术参考指南 (7)—— ATSC数字电视标准

    PS:今天上午,非常郁闷,有很多简单基础的问题搞得我有些迷茫,哎,代码几天不写就忘.目前又不当COO,还是得用心记代码哦! 之前提到过,MPEG-2系统层只能让解码器定位单个TS流上的可用节目和服务. ...

  10. BZOJ 3729: Gty的游戏 [伪ETT 博弈论]【学习笔记】

    题意: 给定一棵有根树,每个节点有一些石子,每次可以将不多于k的石子移动到父节点 修改一个点的石子数,插入一个点,询问某棵子树是否先手必胜 显然是一个阶梯Nim 每次最多取k个,找规律或者观察式子易发 ...

最新文章

  1. 【每日一念经】算法岗面经,一万字面试经验你确定不看?
  2. TensorFlow和ML前5名的课程
  3. java-web的mybatis的学习
  4. UGUI源码之绘制初探
  5. mysql数据库旅游管理系统_JSP+MySQL基于ssm的旅游管理系统
  6. 视频剪辑好帮手——pr软件学习(二)
  7. 服务器发送 微信通知,方糖,使用微信通知的小接口
  8. 面经:中国人民银行金融科技研究院
  9. 独孤九剑第二式-Logistic回归模型
  10. 【学懂数据结构】二叉树之舞之二叉树
  11. 华为又招了一名天才少年!
  12. 在 PHP 中从数组中删除一个元素
  13. K路归并排序与败者树
  14. virtual Box与Vagrant的安装与踩坑
  15. mac address 的一些操作
  16. 威佐夫博弈算法C++
  17. Android OpenGL ES 基础原理
  18. w3c的web标准包括html4吗,web标准以及w3c标准
  19. bdf比特数字基金_PJBlog5 Installer
  20. 计算机软件著作权登记常识

热门文章

  1. DayDayUp:2019.12.31罗振宇2020年跨年演讲《时间的朋友》读后有感—思维决定一个人的上限,能力决定一个人的下限
  2. 虚拟主播?这个项目,我能玩一年!
  3. chrome边解析Html边显示,谷歌浏览器插件侧边翻译Edge Translate
  4. MySQL技能树学习总结
  5. 用流量扫码总显示无法连接服务器,手机有流量但无法连接网络?手机数据网络不能访问互联网...
  6. 新南威尔士 计算机硕士,新南威尔士大学计算机硕士申请条件及案例
  7. php万能每亩,PHP 实现“万能”的短网址还原
  8. U3D Shader基础
  9. 使用theano出错问题
  10. 淘码手机验证码平台——唯一可以批量接收验证码及批量解封账号的平台