[Sdoi2017]树点涂色 [lct 线段树]
[Sdoi2017]树点涂色
题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值
考场发现这个信息是可减的,但是没想到lct
特意设计成lct的形式!
如何求颜色数?
维护一个点和父亲的颜色是否一样,不一样为1,就是前缀和。考虑相邻的思想和那道“水位线”有点像
x到y的答案就是\(S_x + S_y - 2*S_{lca} + 1\)
一个点到根染新颜色,对应了lct的access操作,重边就是一样轻边就是不一样,修改轻重边就是子树加,其他两个操作单点求值,子树求最大值。用线段树维护dfs序
实现上注意:
- access过程中,不能直接修改rc和y,因为splay的形态是不断变化的,应该修改它们所在的splay代表的原树的根
- 并且要先把rc与x重边切断再找根
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int N=1e5+5;
#define fir first
#define sec second
inline int read() {
char c=getchar(); int x=0, f=1;
while(c<'0' || c>'9') {if(c=='-')f=-1; c=getchar();}
while(c>='0' && c<='9') {x=x*10+c-'0'; c=getchar();}
return x*f;
}
int n, Q, op, x, y;
struct edge{int v, ne;} e[N<<1];
int cnt=1, h[N];
inline void ins(int u, int v) {
e[++cnt]=(edge){v, h[u]}; h[u]=cnt;
e[++cnt]=(edge){u, h[v]}; h[v]=cnt;
}
int fa[N], deep[N], size[N], mx[N], top[N], dfc, ver[N];
pair<int, int> dfn[N];
void dfs(int u) {
size[u]=1;
for(int i=h[u];i;i=e[i].ne)
if(e[i].v != fa[u]) {
int v=e[i].v;
fa[v] = u; deep[v] = deep[u]+1;
dfs(v);
size[u] += size[v];
if(size[v] > size[mx[u]]) mx[u] = v;
}
}
void dfs(int u, int anc) {
dfn[u].fir = ++dfc; ver[dfc] = u;
top[u] = anc;
if(mx[u]) dfs(mx[u], anc);
for(int i=h[u];i;i=e[i].ne)
if(e[i].v != fa[u] && e[i].v != mx[u]) dfs(e[i].v, e[i].v);
dfn[u].sec = dfc;
}
inline int lca(int x, int y) {
while(top[x] != top[y]) {
if(deep[top[x]] < deep[top[y]]) swap(x, y);
x = fa[top[x]];
}
return deep[x] < deep[y] ? x : y;
}
namespace seg {
#define mid ((l+r)>>1)
#define lc x<<1
#define rc x<<1|1
#define lson lc, l, mid
#define rson rc, mid+1, r
struct meow{int tag, max;} t[N<<2];
inline void paint(int x, int v) {
t[x].tag += v; t[x].max += v;
}
inline void pushdn(int x) {
if(t[x].tag) {
paint(lc, t[x].tag);
paint(rc, t[x].tag);
t[x].tag = 0;
}
}
inline void merge(int x) {t[x].max = max(t[lc].max, t[rc].max);}
void build(int x, int l, int r) {
if(l == r) t[x].max = deep[ ver[l] ] + 1;
else build(lson), build(rson), merge(x);
}
void add(int x, int l, int r, int ql, int qr, int v) {
if(ql<=l && r<=qr) paint(x, v);
else {
pushdn(x);
if(ql <= mid) add(lson, ql, qr, v);
if(mid < qr ) add(rson, ql, qr, v);
merge(x);
}
}
int que(int x, int l, int r, int p) {
if(l == r) return t[x].max;
else {
pushdn(x);
if(p <= mid) return que(lson, p);
else return que(rson, p);
}
}
int que(int x, int l, int r, int ql, int qr) {
if(ql<=l && r<=qr) return t[x].max;
else {
pushdn(x);
int ans=0;
if(ql <= mid) ans = max(ans, que(lson, ql, qr));
if(mid < qr ) ans = max(ans, que(rson, ql, qr));
return ans;
}
}
#undef lc
#undef rc
}
inline void addsub(int u, int val) {
seg::add(1, 1, n, dfn[u].fir, dfn[u].sec, val);
}
inline void quer(int x, int y) {
int p = lca(x, y);
int ans = seg::que(1, 1, n, dfn[x].fir) + seg::que(1, 1, n, dfn[y].fir) - 2 * seg::que(1, 1, n, dfn[p].fir) + 1;
printf("%d\n", ans);
}
inline void qmax(int x) {
int ans = seg::que(1, 1, n, dfn[x].fir, dfn[x].sec);
printf("%d\n", ans);
}
namespace lct {
#define lc t[x].ch[0]
#define rc t[x].ch[1]
#define pa t[x].fa
struct meow{int ch[2], fa;} t[N];
int sz;
inline int wh(int x) {return t[pa].ch[1] == x;}
inline int isr(int x) {return t[pa].ch[0] != x && t[pa].ch[1] != x;}
inline void rotate(int x) {
int f=t[x].fa, g=t[f].fa, c=wh(x);
if(!isr(f)) t[g].ch[wh(f)] = x; t[x].fa = g;
t[f].ch[c] = t[x].ch[c^1]; t[ t[f].ch[c] ].fa = f;
t[x].ch[c^1] = f; t[f].fa = x;
}
inline void splay(int x) {
for(; !isr(x); rotate(x))
if(!isr(pa)) rotate(wh(x) == wh(pa) ? pa : x);
}
inline int findr(int x) {
splay(x); while(lc) x=lc; splay(x);
return x;
}
void access(int x) {
for(int y=0; x; y=x, x=pa) {
splay(x);
if(rc) {
int u=rc; rc=0;
u=findr(u), addsub(u, 1);
}
if(y) y=findr(y), addsub(y, -1);
rc=y;
}
}
void init() {for(int i=1; i<=n; i++) t[i].fa = fa[i];}
}
int main() {
//freopen("in", "r", stdin);
freopen("paint.in", "r", stdin);
freopen("paint.out", "w", stdout);
n=read(); Q=read();
for(int i=1; i<n; i++) ins(read(), read());
dfs(1); dfs(1, 1); seg::build(1, 1, n); lct::init();
//for(int i=1; i<=n; i++) printf("%d ", ver[i]); puts(" ver");
for(int i=1; i<=Q; i++) {
op=read(); x=read();
if(op==1) lct::access(x);
else if(op==2) y=read(), quer(x, y);
else qmax(x);
}
}
[Sdoi2017]树点涂色 [lct 线段树]的更多相关文章
- 【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][bzoj4817] 树点涂色 [LCT+线段树]
题面 传送门 思路 $LCT$ 我们发现,这个1操作,好像非常像$LCT$里面的$Access$啊~ 那么我们尝试把$Access$操作魔改成本题中的涂色 我们令$LCT$中的每一个$splay$链代 ...
- BZOJ 4817 [SDOI2017]树点涂色 (LCT+线段树维护dfs序)
题目大意:略 涂色方式明显符合$LCT$里$access$操作的性质,相同颜色的节点在一条深度递增的链上 用$LCT$维护一个树上集合就好 因为它维护了树上集合,所以它别的啥都干不了了 发现树是静态的 ...
- BZOJ4817[Sdoi2017]树点涂色——LCT+线段树
题目描述 Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进 ...
- bzoj4817 & loj2001 [Sdoi2017]树点涂色 LCT + 线段树
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4817 https://loj.ac/problem/2001 题解 可以发现这个题就是 bzo ...
- 【bzoj4817】树点涂色 LCT+线段树+dfs序
Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...
- BZOJ 4817 [Sdoi2017]树点涂色 ——LCT 线段树
同BZOJ3779. SDOI出原题,还是弱化版的. 吃枣药丸 #include <map> #include <cmath> #include <queue> # ...
- BZOJ 4817: [Sdoi2017]树点涂色(lct+线段树)
传送门 解题思路 跟重组病毒这道题很像.只是有了一个询问\(2\)的操作,然后询问\(2\)的答案其实就是\(val[x]+val[y]-2*val[lca(x,y)]+1\)(画图理解).剩下的操作 ...
随机推荐
- HDU1016(素数环)
Prime Ring Problem Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- android动画源码合集、动态主题框架、社交app源码等
Android精选源码 仿MIUI果冻视图-BouncingJellyView 一个快速易用的动态主题框架 android动画效果集合源码 android使用Kotlin开发的Dribbb ...
- JAVA爬虫实践(实践三:爬虫框架webMagic和csdnBlog爬虫)
WebMagic WebMagic是一个简单灵活的Java爬虫框架.基于WebMagic,你可以快速开发出一个高效.易维护的爬虫. 采用HttpClient可以实现定向的爬虫,也可以自己编写算法逻辑来 ...
- Spider_Man_5.2 の Mongodb_使用
一:简介 MongoDB是一款强大.灵活.且易于扩展的通用型数据库1.易用性 MongoDB是一个面向文档(document-oriented)的数据库,而不是关系型数据库.不采用关系型主要是为了获得 ...
- SVN版本库修改URL路径或者IP地址
服务器的IP地址或者URL变更,版本库服务器的IP也要修改,因为当初安装SVN URL没有使用别名,所以使用的人都要修改客户端的IP,以下是参考网上的资料. 1.Windows TortoiseSVN ...
- protobuf 原理
Protobuf 的优点 Protobuf 有如 XML,不过它更小.更快.也更简单.你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构.你甚至可以在无需重新部署程序的情况下更新 ...
- PostgresSQL中的限制和级联删除
摘录自:http://www.mamicode.com/info-detail-879792.html 删除和更新时对应的操作是一样的
- python-虎扑爬虫
Python作为一个高级编程语言,不知从何时起就在圈子里流行起来了.个人也是图个鲜,跟上时代步伐学习了一下."鲁迅"说过:不能学以致用,就是耍流氓.我用python对虎扑论坛作了一 ...
- Linux系统shell编程自学_第一章基础
第一章 基础shell的优势在于处理操作系统底层的业务,Python,php的优势在于开发运维工具,web界面的管理工具以及web业务开发.处理一键安装.优化.报警脚本shell又叫命令解释器,它能识 ...
- js 获取url链接的任意参数
<script> //先获取 当前的url链接 var url = location.href; //把url 链接切割为数组 var arr = url.split("&quo ...