luogu3703 [SDOI2017]树点涂色(线段树+树链剖分+动态树)
你谷的第一篇题解没用写LCT,然后没观察懂,但是自己YY了一种不用LCT的做法
我们考虑对于每个点,维护一个fa,代表以1为根时候这个点的父亲
再维护一个bel,由于一个颜色相同的段一定是一个深度递增的链,这个代表颜色段的链顶
再维护一个ans,就是ans
那么第二个操作就是ans单点查询,第三个就是ans区间最大值
第一个操作,我们树剖把它变成了log条重链,在重链上的点的bel和ans可以区间修改
但是重链上每个点的儿子就说gg了
这些儿子的子树减去的是他们的各自bel的fa的点权,然后在加上一个1
所以说每个点还要维护一个preferred child,显然很难写(但是应该是可以实现的),还是写动态树吧
动态树其实是动态树的阉割版,我们用一个splay维护树中颜色相同的点,显然这种点一定是一段深度递增的链,于是你会发现只需要钦定1为根,操作1就是access
然后我们可以维护每个点操作3的ans,再搞个dfn,操作3就可以用线段树维护,然而每个点的答案就相当于动态树上这个点到根节点上虚边的个数+1,我们可以搞个线段树维护,在动态树access虚实变化时候搞个区间加法即可
然后你会发现对于操作2的x,y答案就是ans[x] + ans[y] - 2 * ans[lc] + 1,所以说我们还需要支持一个lca操作,写个树剖或者倍增就行了,我为了凑齐全家桶就写了个树剖
注意树剖的fa和lct的fa一开始是一个fa,lct的fa是动态维护的,树剖的fa是静态的,要开两个数组并且别弄混了,调了好长时间...
access过程中由于变换的是深度恰好为depth[x]+1的点,所以就要对x寻找后继,就是x的右儿子不停往左跳。。。
时间复杂度Nlog^2N
#include <cstdio>
#include <vector>
using namespace std;
//区间加法,区间取max
int fa[100010], dfn[100010], depth[100010], weight[100010], wson[100010], top[100010];
int tree[400010], lazy[400010], fuck[100010], ch[100010][2], fat[100010], tot, n, m;
vector<int> out[100010];
void init(int x, int cl, int cr)
{
if (cl == cr)
{
tree[x] = fuck[cl];
}
else
{
int mid = (cl + cr) / 2;
init(x * 2, cl, mid), init(x * 2 + 1, mid + 1, cr);
tree[x] = max(tree[x * 2], tree[x * 2 + 1]);
}
}
void pushdown(int x)
{
tree[x * 2] += lazy[x], tree[x * 2 + 1] += lazy[x];
lazy[x * 2] += lazy[x], lazy[x * 2 + 1] += lazy[x];
lazy[x] = 0;
}
void chenge(int x, int cl, int cr, int L, int R, int val)
{
if (cr < L || R < cl) return;
if (L <= cl && cr <= R) { tree[x] += val, lazy[x] += val; return; }
pushdown(x);
int mid = (cl + cr) / 2;
chenge(x * 2, cl, mid, L, R, val);
chenge(x * 2 + 1, mid + 1, cr, L, R, val);
tree[x] = max(tree[x * 2], tree[x * 2 + 1]);
}
int query(int x, int cl, int cr, int L, int R)
{
if (cr < L || R < cl) return 0;
if (L <= cl && cr <= R) return tree[x];
pushdown(x);
int mid = (cl + cr) / 2;
return max(query(x * 2, cl, mid, L, R), query(x * 2 + 1, mid + 1, cr, L, R));
}
void dfs1(int x)
{
weight[x] = 1, wson[x] = -1;
for (int i : out[x]) if (fa[x] != i)
{
fa[i] = fat[i] = x, depth[i] = depth[x] + 1;
dfs1(i), weight[x] += weight[i];
if (wson[x] == -1 || weight[wson[x]] < weight[i]) wson[x] = i;
}
}
void dfs2(int x, int topf)
{
dfn[x] = ++tot, top[x] = topf, fuck[dfn[x]] = depth[x] + 1;
if (wson[x] == -1) return;
dfs2(wson[x], topf);
for (int i : out[x]) if (fa[x] != i && wson[x] != i) dfs2(i, i);
}
int lca(int x, int y)
{
while (top[x] != top[y])
{
if (depth[top[x]] < depth[top[y]]) swap(x, y);
x = fa[top[x]];
}
if (depth[x] > depth[y]) swap(x, y);
return x;
}
bool nroot(int x) { return ch[fat[x]][0] == x || ch[fat[x]][1] == x; }
void rotate(int x)
{
int y = fat[x], z = fat[y], k = ch[y][1] == x, w = ch[x][k ^ 1];
if (nroot(y)) { ch[z][ch[z][1] == y] = x; } ch[x][k ^ 1] = y, ch[y][k] = w;
if (w) { fat[w] = y; } fat[y] = x; fat[x] = z;
}
void splay(int x)
{
while (nroot(x))
{
int y = fat[x], z = fat[y];
if (nroot(y)) rotate((ch[y][1] == x) ^ (ch[z][1] == y) ? x : y);
rotate(x);
}
}
int findrt(int x)
{
while (ch[x][0]) x = ch[x][0];
return x;
}
void access(int x)
{
for (int y = 0; x > 0; x = fat[y = x])
{
splay(x);
if (ch[x][1])
{
int p = findrt(ch[x][1]);
chenge(1, 1, n, dfn[p], dfn[p] + weight[p] - 1, 1);
}
ch[x][1] = y;
if (y)
{
int p = findrt(y);
chenge(1, 1, n, dfn[p], dfn[p] + weight[p] - 1, -1);
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int x, y, i = 1; i < n; i++) scanf("%d%d", &x, &y), out[x].push_back(y), out[y].push_back(x);
dfs1(1), dfs2(1, 1); init(1, 1, n);
for (int opd, x, y, i = 1; i <= m; i++)
{
scanf("%d%d", &opd, &x);
if (opd == 1) access(x);
if (opd == 2)
{
scanf("%d", &y);
int lc = lca(x, y);
printf("%d\n", query(1, 1, n, dfn[x], dfn[x]) + query(1, 1, n, dfn[y], dfn[y]) - 2 * query(1, 1, n, dfn[lc], dfn[lc]) + 1);
}
if (opd == 3) printf("%d\n", query(1, 1, n, dfn[x], dfn[x] + weight[x] - 1));
}
return 0;
}
luogu3703 [SDOI2017]树点涂色(线段树+树链剖分+动态树)的更多相关文章
- URAL1553 Caves and Tunnels 树链剖分 动态树
URAL1553 维护一棵树,随时修改某个节点的权值,询问(x,y)路径上权值最大的点. 树是静态的,不过套动态树也能过,时限卡的严就得上树链剖分了. 还是那句话 splay的核心是splay(x) ...
- [Sdoi2017]树点涂色 [lct 线段树]
[Sdoi2017]树点涂色 题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值 考场发现这个信息是可减的,但是没想到lct 特意设计成lct的形式! 如何求颜色数? ...
- [BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 692 Solved: 408[Submit][Status ...
- 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树
[BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...
- 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]
树点涂色 Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中1 ...
- 「SDOI2017」树点涂色 解题报告
「SDOI2017」树点涂色 我sb的不行了 其实一开始有一个类似动态dp的想法 每个点维护到lct树上到最浅点的颜色段数,然后维护一个\(mx_{0,1}\)也就是是否用虚儿子的最大颜色 用个set ...
- P3703 [SDOI2017]树点涂色
P3703 [SDOI2017]树点涂色 链接 分析: 首先对于询问,感觉是线段树维护dfs序,每个点记录到根的颜色个数.第二问差分,第三问区间取max. 那么考虑修改,每次将一个点的颜色变成和父节点 ...
- [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 629 Solved: 371[Submit][Status ...
- 【LG3703】[SDOI2017]树点涂色
[LG3703][SDOI2017]树点涂色 题面 洛谷 题解 更博辣,更博辣!!! 猪年的第一篇博客 一次只能染根到\(x\),且染的颜色未出现过 这句话是我们解题的关键. 设\(x\)到根的颜色数 ...
随机推荐
- Java微信公众平台开发--番外篇,对GlobalConstants文件的补充
转自:http://www.cuiyongzhi.com/post/63.html 之前发过一个[微信开发]系列性的文章,也引来了不少朋友观看和点评交流,可能我在写文章时有所疏忽,对部分文件给出的不是 ...
- Timer的定义及demo
- Spring总结七:AOP动态代理的实现
Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类. 首先我们来用代码简单演示jdk动态代理: 现在有一个商品的增删改查的操作 /** * 商品操作接口 ...
- /error处理
1 BasicErrorController 1.1 简述 SpringMVC框架在出现错误时有一个默认的错误请求 /error:出现异常之后执行/error请求之前框架会判断出现异常的请求类型,然后 ...
- MySQL5.7插入中文乱码
参考: https://blog.csdn.net/kelay06/article/details/60870138 https://blog.csdn.net/itmr_liu/article/de ...
- Luogu 4869 albus就是要第一个出场
BZOJ 2844 被NOIP模拟赛题弄自闭了QuQ. 因为本题要求异或,所以自然地构造出线性基,假设本题中给出的数有$n$个,而我们构造出的线性基大小为$m$,那么每一个可以异或出来的数相当于出现了 ...
- 登录xdebug
1.配置 2.先不打断点,调至登录页面 3.在登录必经过处打断点,访问页面输入账号密码点击登录,进入代码追踪模式
- github如何上传代码
别人写的太好了,没必要重写.备份给自己参看. 1.https://www.cnblogs.com/zlxbky/p/7727895.html 2.https://blog.csdn.net/pql92 ...
- 数据库 MySQL 之 表操作、存储引擎
数据库 MySQL 之 表操作.存储引擎 浏览目录 创建(复制) 删除 修改 查询 存储引擎介绍 一.创建(复制) 1.语法: 1 2 3 4 5 CREATE TABLE 表名( 字段名1 ...
- Git教程--廖雪峰
Git简介 1.Git是目前世界上最先进的分布式版本控制系统(没有之一) 2.集中式和分布式版本控制系统有什么区别呢? 区别在于历史版本维护的位置:Git本地仓库包含代码库还有历史库,在本地 ...