【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]
树点涂色
Time Limit: 10 Sec Memory Limit: 128 MB
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
1 2
2 3
3 4
3 5
2 4 5
3 3
1 4
2 4 5
1 5
2 4 5
Sample Output
4
2
2
HINT
Solution
我们将边两端的点颜色相同的边设为实边,不同的设为虚边。那么一次新增颜色的操作显然就是LCT的access操作!access的时候恰是虚边和实边的转换。
那么我们只要用线段树维护每个点到根的贡献,结合dfs序来实现子树加,每次在LCT进行access的时候进行+-1修改,然后询问的时候用区间求和,区间最值求得答案即可。
Code
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long s64; const int ONE = 2e5+; int n,m;
int x,y,P;
int POS[ONE],POSCNT;
int pos[ONE],dfn_cnt,size[ONE],dfn[ONE];
int Dep[ONE],son[ONE],Top[ONE];
int lc[ONE],rc[ONE],fa[ONE],fat[ONE];
int res_max,res_value; inline int get()
{
int res=,Q=; char c;
while( (c=getchar())< || c>)
if(c=='-')Q=-;
if(Q) res=c-;
while((c=getchar())>= && c<=)
res=res*+c-;
return res*Q;
} namespace tree
{
int next[ONE],first[ONE],go[ONE],tot=; void Add(int u,int v)
{
next[++tot]=first[u]; first[u]=tot; go[tot]=v;
next[++tot]=first[v]; first[v]=tot; go[tot]=u;
} void Dfs(int u,int father)
{
pos[u] = ++dfn_cnt; dfn[dfn_cnt] = u;
size[u] = ;
Dep[u] = Dep[father] + ;
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father) continue;
fa[v] = u; fat[v] = u;
Dfs(v,u);
size[u] += size[v];
if(size[v] > size[son[u]]) son[u] = v;
}
} void Dfs_twice(int u,int father)
{
POS[u] = ++POSCNT;
if(son[u])
{
int v=son[u];
Top[v] = Top[u];
Dfs_twice(v,u);
} for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father || v==son[u]) continue;
Top[v] = v;
Dfs_twice(v,u);
}
} int LCA(int x,int y)
{
while(Top[x]!=Top[y])
{
if( Dep[Top[x]] < Dep[Top[y]] ) swap(x,y);
x = fat[Top[x]];
}
if(POS[x] > POS[y]) swap(x,y);
return x;
}
} namespace Seg
{
struct power
{
int add,value;
int maxx;
}Node[ONE*]; void pushdown(int i,int Q)
{
if(Node[i].add)
{
Node[i<<].add += Node[i].add;
Node[i<<|].add += Node[i].add;
Node[i<<].maxx += Node[i].add;
Node[i<<|].maxx += Node[i].add;
Node[i<<].value += Node[i].add * (Q-Q/);
Node[i<<|].value += Node[i].add * (Q/);
Node[i].add = ;
}
} void Build(int i,int l,int r)
{
if(l==r)
{
Node[i].value = Dep[dfn[l]];
Node[i].maxx = Dep[dfn[l]];
return ;
}
int mid = l+r>>;
Build(i<<,l,mid); Build(i<<|,mid+,r);
Node[i].value = Node[i<<].value + Node[i<<|].value;
Node[i].maxx = max(Node[i<<].maxx, Node[i<<|].maxx);
} void Update(int i,int l,int r,int L,int R,int x)
{
if(L<=l && r<=R)
{
Node[i].add += x;
Node[i].value += (r-l+)*x;
Node[i].maxx += x;
return;
}
pushdown(i,r-l+);
int mid = l+r>>;
if(L<=mid) Update(i<<,l,mid,L,R,x);
if(mid+<=R) Update(i<<|,mid+,r,L,R,x); Node[i].value = Node[i<<].value + Node[i<<|].value;
Node[i].maxx = max(Node[i<<].maxx , Node[i<<|].maxx);
} void Query(int i,int l,int r,int L,int R)
{
if(L<=l && r<=R)
{
res_max = max(res_max,Node[i].maxx);
res_value += Node[i].value;
return;
}
pushdown(i,r-l+);
int mid = l+r>>;
if(L<=mid) Query(i<<,l,mid,L,R);
if(mid+<=R) Query(i<<|,mid+,r,L,R);
}
} namespace LCT
{
int is_real(int x)
{
return (lc[fa[x]]==x || rc[fa[x]]==x);
} void Turn(int x)
{
int y = fa[x], z = fa[y];
int b = x==lc[y] ? rc[x]:lc[x]; fa[x] = z; fa[y] = x;
if(b) fa[b] = y; if(z)
{
if(y == lc[z]) lc[z] = x;
else
if(y == rc[z]) rc[z] = x;
} if(x==lc[y]) rc[x]=y,lc[y]=b;
else lc[x]=y,rc[y]=b;
} void Splay(int x)
{
while(is_real(x))
{
if(is_real(fa[x]))
{
if( (lc[fa[x]]==x) == (lc[fa[fa[x]]]==fa[x])) Turn(fa[x]);
else Turn(x);
}
Turn(x);
}
} int find_root(int x)
{
while(lc[x]) x=lc[x];
return x;
} void access(int x)
{
for(int p=x,q=; p; q=p,p=fa[p])
{
Splay(p);
if(rc[p])
{
int N = find_root(rc[p]);
Seg::Update(,,n,pos[N],pos[N]+size[N]-,);
} rc[p] = q;
if(rc[p])
{
int N = find_root(rc[p]);
Seg::Update(,,n,pos[N],pos[N]+size[N]-,-);
}
}
}
} int Getsum(int x,int y)
{
int Ans, Sx, Sy, SLCA, LCA;
LCA = tree::LCA(x,y);
x=pos[x], y=pos[y], LCA=pos[LCA];
res_value = ; Seg::Query(,,n,x,x); Sx = res_value;
res_value = ; Seg::Query(,,n,y,y); Sy = res_value;
res_value = ; Seg::Query(,,n,LCA,LCA); SLCA = res_value;
return Sx+Sy-*SLCA+;
} int Getmax(int x)
{
res_max = ;
Seg::Query(,,n,pos[x],pos[x]+size[x]-);
return res_max;
} int main()
{
n=get(); m=get();
for(int i=;i<=n-;i++)
{
x=get(); y=get();
tree::Add(x,y);
} tree::Dfs(,);
Top[] = , tree::Dfs_twice(,);
Seg::Build(,,n); while(m--)
{
P = get(); x=get();
if(P==)
LCT::access(x);
if(P==)
y=get(), printf("%d\n",Getsum(x,y));
if(P==)
printf("%d\n",Getmax(x));
}
}
【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]的更多相关文章
- 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树
[BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...
- [Sdoi2017]树点涂色 [lct 线段树]
[Sdoi2017]树点涂色 题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值 考场发现这个信息是可减的,但是没想到lct 特意设计成lct的形式! 如何求颜色数? ...
- [SDOI2017][bzoj4817] 树点涂色 [LCT+线段树]
题面 传送门 思路 $LCT$ 我们发现,这个1操作,好像非常像$LCT$里面的$Access$啊~ 那么我们尝试把$Access$操作魔改成本题中的涂色 我们令$LCT$中的每一个$splay$链代 ...
- 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 ...
- BZOJ 4817 [SDOI2017]树点涂色 (LCT+线段树维护dfs序)
题目大意:略 涂色方式明显符合$LCT$里$access$操作的性质,相同颜色的节点在一条深度递增的链上 用$LCT$维护一个树上集合就好 因为它维护了树上集合,所以它别的啥都干不了了 发现树是静态的 ...
- 【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\)(画图理解).剩下的操作 ...
随机推荐
- LintCode-212.空格替换
空格替换 设计一种方法,将一个字符串中的所有空格替换成 %20 .你可以假设该字符串有足够的空间来加入新的字符,且你得到的是"真实的"字符长度. 你的程序还需要返回被替换后的字符串 ...
- Qt代码覆盖率code coverage(VS版)
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt代码覆盖率code coverage(VS版) 本文地址:http://techi ...
- 在intelllij中debug的时候使用log4j输出
一般在本地调试的时候,在控制台打印输出都会使用system.out.print,但是在线上运行的时候一般都是使用log4j进行日志输出. 那么在编写代码的时候,又不想写两份,直接写LOG是常规动作. ...
- HTML5+ API 学习
HTML5+ API 模块整理 API Reference 模块 中文 模块介绍 Accelerometer 加速计 管理设备加速度传感器,用于获取设备加速度信息,包括x(屏幕水平方向).y(垂直屏幕 ...
- Luogu3936 Coloring(模拟退火)
裸退火,每次交换两个格子即可.依旧不会调参,稍微抄了点参数并且把随机种子设成了一个神奇的数字终于过掉了. #include<iostream> #include<cstdio> ...
- 虚拟机如何设置U盘启动项
开始配置虚拟机时选"自定义"不要选"典型",在“SCSI设配器”选LSI logic ,(不是默认的那个):然后其他正常默认创建,虚拟机建好后,再添加U盘为虚拟 ...
- [USACO06NOV]玉米田Corn Fields 状压DP
题面: 农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地.John打算在牧场上的某几格里种上美味的草,供他的 ...
- Python3简单入门
在Mac和Linux上运行Python时,请打开终端,然后运行python3 Mac OSX 正确地同时安装Python 2.7 和Python3: http://www.jianshu.com/p ...
- poj2409:Let it Bead(置换群 polya定理)
题目大意:长度为n的项链,要染m种颜色,可以通过旋转或翻转到达的状态视为同一种,问有多少种染色方案. 学了一波polya定理,发现很好理解啊,其实就是burnside定理的扩展. burnside定理 ...
- JSP页面中的Meta标签详解
Meta标签详解 相信大家在平时开发中最常接触的页面就是html和jsp了,可在这两个页面中有一个Meta标签你天天都会看见,可是你真的了解这个标签的一些其他用处吗?今天给大家介绍一些该标签的其他应用 ...