【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\)(画图理解).剩下的操作 ...
随机推荐
- 20145214实验四 Android开发基础
20145214实验四 Android开发基础 实验内容及步骤 安装 JDK 并配置 JDK 环境变量 找到之前path变量中的jdk文件所在位置并复制. 用复制的变量名新建一个 JAVA_HOME ...
- c# CLR无法从 COM 上下文 0x51cd20 转换为 COM 上下文 0x51ce90
调试菜单--->异常---->managed debugging assistants栏下ContextSwitchDeadlock 前面的√去掉
- Qt窗口及控件-窗口Close()自动释放
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt-窗口Close()后自动释放空间 本文地址:http://techieliang ...
- oracle 9i 图文安装教程 oracle 9i 安装
我的安装文件是ISO镜像文件,使用Virtual DAEMON Manager v 4.10打开: ora9i-1.iso ora9i-2.iso ora9i-3.iso 首先必须把上面三个镜像文件都 ...
- mac终端命令-----常规操作
OSX 的文件系统 OSX 采用的Unix文件系统,所有文件都挂在跟目录 / 下面,所以不在要有Windows 下的盘符概念. 你在桌面上看到的硬盘都挂在 /Volumes 下. 比如接上个叫做 US ...
- 三节点搭建openstack-Mitaka版本
前言: 现在的云计算平台已经非常火,也非常的稳定了.像阿里云平台,百度云平台等等,今天咱们基于openstack来搭建一个云平台 注意: 本次平台搭建为三节点搭建(没有外部存储节点,所有存储为本地存储 ...
- 51nod 1304 字符串的相似度(exkmp)
拓展kmp裸题 自己跟自己匹配即可 模板测试=v= #include <iostream> #include <cstring> using namespace std; ; ...
- ARC072 D Alice&Brown 博弈论
---题面--- 题解: 题目大意:有2堆石子数分别为x, y的石子,你每次可以从中间的某一堆中取出2i个石子,扔掉i个,并把剩下的i个放到另一堆,无法操作的人就输了. 现在给定x,y,判断先手必赢还 ...
- POJ2074:Line of Sight——题解
http://poj.org/problem?id=2074 题目大意:(下面的线段都与x轴平行)给两条线段,一个点在其中一条线段看另一条线段,但是中间有很多线段阻挡视线.求在线段上最大连续区间使得在 ...
- BZOJ3165 & 洛谷4097:[HEOI2013]Segment——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3165 https://www.luogu.org/problemnew/show/P4097 要求 ...