[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 线段树]的更多相关文章

  1. 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树

    [BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...

  2. 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]

    树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中1 ...

  3. [SDOI2017][bzoj4817] 树点涂色 [LCT+线段树]

    题面 传送门 思路 $LCT$ 我们发现,这个1操作,好像非常像$LCT$里面的$Access$啊~ 那么我们尝试把$Access$操作魔改成本题中的涂色 我们令$LCT$中的每一个$splay$链代 ...

  4. BZOJ 4817 [SDOI2017]树点涂色 (LCT+线段树维护dfs序)

    题目大意:略 涂色方式明显符合$LCT$里$access$操作的性质,相同颜色的节点在一条深度递增的链上 用$LCT$维护一个树上集合就好 因为它维护了树上集合,所以它别的啥都干不了了 发现树是静态的 ...

  5. BZOJ4817[Sdoi2017]树点涂色——LCT+线段树

    题目描述 Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进 ...

  6. bzoj4817 & loj2001 [Sdoi2017]树点涂色 LCT + 线段树

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4817 https://loj.ac/problem/2001 题解 可以发现这个题就是 bzo ...

  7. 【bzoj4817】树点涂色 LCT+线段树+dfs序

    Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...

  8. BZOJ 4817 [Sdoi2017]树点涂色 ——LCT 线段树

    同BZOJ3779. SDOI出原题,还是弱化版的. 吃枣药丸 #include <map> #include <cmath> #include <queue> # ...

  9. BZOJ 4817: [Sdoi2017]树点涂色(lct+线段树)

    传送门 解题思路 跟重组病毒这道题很像.只是有了一个询问\(2\)的操作,然后询问\(2\)的答案其实就是\(val[x]+val[y]-2*val[lca(x,y)]+1\)(画图理解).剩下的操作 ...

随机推荐

  1. ACM_扩展欧几里德算法

    <pre name="code" class="cpp">/* 扩展欧几里德算法 基本算法:对于不完全为 0 的非负整数 a,b,gcd(a,b)表 ...

  2. WEB 小案例 -- 网上书城(一)

    距离上次写博客有两周了吧,最多的原因就是自己期末考试了,上课没听就只能在期末狠狠的复习了,毕竟已经挂科了.当然还是因为自己懒吧!!!废话不多说开始我们今天的正题,网上书城! 一. 新建数据表(MySQ ...

  3. 一步步教你创建自己的数字货币(代币)进行ICO

    本文从技术角度详细介绍如何基于以太坊ERC20创建代币的流程. 写在前面 本文所讲的代币是使用以太坊智能合约创建,阅读本文前,你应该对以太坊.智能合约有所了解,如果你还不了解,建议你先看以太坊是什么 ...

  4. Pycharm+django新建Python Web项目

    这两天初学Python,首先是学习Python语法有PyCharm就可以运行Console程序了,因为是初学所以,尽量写的比较详细,包括参考的资料地址...   1.下载Python,并安装[本文版本 ...

  5. HDU 1069 Monkey and Banana(DP——最大递减子序列)

    题目链接: http://acm.split.hdu.edu.cn/showproblem.php?pid=1069 题意描述: 给n块砖,给出其长,宽和高 问将这n块砖,怎样叠放使得满足以下条件使得 ...

  6. NYOJ 1248 海岛争霸(Dijkstra变形——最短路径最大权值)

    题目链接: http://acm.nyist.net/JudgeOnline/problem.php?pid=1248 描述 神秘的海洋,惊险的探险之路,打捞海底宝藏,激烈的海战,海盗劫富等等.加勒比 ...

  7. 使用python爬取百度贴吧内的图片

    1. 首先通过urllib获取网页的源码 # 定义一个getHtml()函数 def getHtml(url): try: page = urllib.urlopen(url) # urllib.ur ...

  8. php switch case语句用法

  9. 认识Java(2)

    注释 对程序的一段文字描述 可方便其他用户的阅读,增加代码的可读性.可以注销掉代码,等需要的时候再用. 编译器会自动忽视被注释的内容. 分类: 单行注释 // 多行注释 /* */ 文档注释/** * ...

  10. Sublime Text 2激活、插件包安装、以及快捷键

    http://jingyan.baidu.com/article/ff4116259b057c12e48237b8.html Sublime Text作为一款轻量.简洁.高效.跨平台的编辑器.支持N多 ...