bzoj4817 [Sdoi2017]树点涂色
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
正解:$link-cut tree$+树链剖分+线段树。
这道题很巧妙啊。。利用$LCT$的神奇性质完美地解决了询问$1$的棘手操作。
首先我们注意到,询问$1$其实就是$LCT$中的$access$操作。我们可以直接维护每个点到根节点的权值,然后利用$access$操作来处理这个问题。
我们在$access$操作的时候,直接将当前点原来的实儿子所在的子树权值$+1$,当前待接上的实儿子所在子树权值$-1$,就能完美地处理这个操作了。注意,这里指的实儿子一定是在原树中深度最浅的点。我比较偷懒,就直接暴力找$splay$中深度最小的点。具体解释的话,画个图就能理解了,看下代码应该能弄懂吧。。
对于询问$2$,我们可以发现,路径上的权值就是$val[x]+val[y]-2*val[lca(x,y)]+1$。这个式子是很好画图证明的。
首先,$lca$的两个儿子颜色是不可能相同的,所以我们分两种情况讨论一下,一种是$lca$和其中一个儿子颜色相同,一种是$lca$和两个儿子颜色都不同。这样我们就能很容易地得出上述结论。
对于询问$3$,我们直接区间查询,询问子树中的权值最大值就行了。
以上操作,维护权值都是用线段树,求$lca$写树链剖分比较方便。然后我们就能$AC$此题了,虽然复杂度还是很玄学。。
第一次$bzoj \ rank1$。。
//It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf (1<<30)
#define N (100010)
#define ls (x<<1)
#define rs (x<<1|1)
#define il inline
#define RG register
#define ll long long
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) using namespace std; struct edge{ int nt,to; }g[*N]; int head[N],n,m,num; struct tree_cut{ int top[N],fa[N],son[N],sz[N],dep[N],pos[N],tid[N],ed[N],cnt; il void dfs1(RG int x,RG int p){
fa[x]=p,dep[x]=dep[p]+,sz[x]=; RG int v;
for (RG int i=head[x];i;i=g[i].nt){
v=g[i].to; if (v==p) continue;
dfs1(v,x),sz[x]+=sz[v];
if (sz[son[x]]<=sz[v]) son[x]=v;
}
return;
} il void dfs2(RG int x,RG int p,RG int anc){
top[x]=anc,tid[x]=++cnt,pos[cnt]=x;
if (son[x]) dfs2(son[x],x,anc); RG int v;
for (RG int i=head[x];i;i=g[i].nt){
v=g[i].to; if (v==p || v==son[x]) continue;
dfs2(v,x,v);
}
ed[x]=cnt; return;
} il int lca(RG int u,RG int v){
while (top[u]!=top[v]){
if (dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v] ? u : v;
} }tree; struct segment_tree{ int mx[*N],lazy[*N]; il void pushdown(RG int x){
mx[ls]+=lazy[x],mx[rs]+=lazy[x];
lazy[ls]+=lazy[x],lazy[rs]+=lazy[x];
lazy[x]=; return;
} il void build(RG int x,RG int l,RG int r){
if (l==r){ mx[x]=tree.dep[tree.pos[l]]; return; }
RG int mid=(l+r)>>;
build(ls,l,mid),build(rs,mid+,r);
mx[x]=max(mx[ls],mx[rs]); return;
} il void update(RG int x,RG int l,RG int r,RG int xl,RG int xr,RG int v){
if (xl<=l && r<=xr){ mx[x]+=v,lazy[x]+=v; return; }
if (lazy[x]) pushdown(x); RG int mid=(l+r)>>;
if (xr<=mid) update(ls,l,mid,xl,xr,v);
else if (xl>mid) update(rs,mid+,r,xl,xr,v);
else update(ls,l,mid,xl,mid,v),update(rs,mid+,r,mid+,xr,v);
mx[x]=max(mx[ls],mx[rs]); return;
} il int querymax(RG int x,RG int l,RG int r,RG int xl,RG int xr){
if (xl<=l && r<=xr) return mx[x];
if (lazy[x]) pushdown(x); RG int mid=(l+r)>>;
if (xr<=mid) return querymax(ls,l,mid,xl,xr);
else if (xl>mid) return querymax(rs,mid+,r,xl,xr);
else return max(querymax(ls,l,mid,xl,mid),querymax(rs,mid+,r,mid+,xr));
} il int ask(RG int x){ return querymax(,,n,tree.tid[x],tree.tid[x]); } }seg; struct link_cut_tree{ int ch[N][],fa[N]; il int isroot(RG int x){
return ch[fa[x]][]!=x && ch[fa[x]][]!=x;
} il void rotate(RG int x){
RG int y=fa[x],z=fa[y],k=ch[y][]==x;
if (!isroot(y)) ch[z][ch[z][]==y]=x;
fa[x]=z,ch[y][k^]=ch[x][k],fa[ch[x][k]]=y;
ch[x][k]=y,fa[y]=x; return;
} il void splay(RG int x){
while (!isroot(x)){
RG int y=fa[x],z=fa[y];
if (!isroot(y)){
if ((ch[y][]==x)^(ch[z][]==y)) rotate(x);
else rotate(y);
}
rotate(x);
}
return;
} il void access(RG int x){
RG int t=;
while (x){
splay(x);
if (ch[x][]){
RG int y=ch[x][]; while (ch[y][]) y=ch[y][];
seg.update(,,n,tree.tid[y],tree.ed[y],);
}
if (t){
RG int y=t; while (ch[y][]) y=ch[y][];
seg.update(,,n,tree.tid[y],tree.ed[y],-);
}
ch[x][]=t,t=x,x=fa[x];
}
return;
} }lct; il void insert(RG int from,RG int to){
g[++num]=(edge){head[from],to},head[from]=num; return;
} il int gi(){
RG int x=,q=; RG char ch=getchar();
while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar();
while (ch>='' && ch<='') x=x*+ch-,ch=getchar();
return q*x;
} il void work(){
n=gi(),m=gi();
for (RG int i=,u,v;i<n;++i) u=gi(),v=gi(),insert(u,v),insert(v,u);
tree.dfs1(,),tree.dfs2(,,),seg.build(,,n);
for (RG int i=;i<=n;++i) lct.fa[i]=tree.fa[i];
for (RG int i=,type,x,y;i<=m;++i){
type=gi(); if (type==) x=gi(),lct.access(x);
if (type==){
x=gi(),y=gi(); RG int Lca=tree.lca(x,y);
printf("%d\n",seg.ask(x)+seg.ask(y)-*seg.ask(Lca)+);
}
if (type==) x=gi(),printf("%d\n",seg.querymax(,,n,tree.tid[x],tree.ed[x]));
}
return;
} int main(){
File("paint");
work();
return ;
}
bzoj4817 [Sdoi2017]树点涂色的更多相关文章
- [BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)
		
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 692 Solved: 408[Submit][Status ...
 - [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)
		
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 629 Solved: 371[Submit][Status ...
 - BZOJ4817[Sdoi2017]树点涂色——LCT+线段树
		
题目描述 Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进 ...
 - BZOJ4817 [Sdoi2017]树点涂色  【LCT + 线段树】
		
题目 Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进行这 ...
 - bzoj千题计划275:bzoj4817: [Sdoi2017]树点涂色
		
http://www.lydsy.com/JudgeOnline/problem.php?id=4817 lct+线段树+dfs序 操作1:access 操作2:u到根的-v到根的-lca到根的*2+ ...
 - BZOJ4817: [Sdoi2017]树点涂色(LCT)
		
Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...
 - [BZOJ4817][SDOI2017]树点涂色:Link-Cut Tree+线段树
		
分析 与[BZOJ3779]重组病毒唯一的区别是多了一个链上求实链段数的操作. 因为每条实链的颜色必然不相同且一条实链上不会有两个深度相同的点(好像算法的正确性和第二个条件没什么关系,算了算了),画图 ...
 - 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树
		
[BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...
 - [Sdoi2017]树点涂色 [lct 线段树]
		
[Sdoi2017]树点涂色 题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值 考场发现这个信息是可减的,但是没想到lct 特意设计成lct的形式! 如何求颜色数? ...
 
随机推荐
- HTML+CSS-采用DIV+CSS布局的利弊
			
单纯的TABLE表格,在浏览器运行上面来说,其效率不如DIV+CSS方式快速,当然,这样也就会影响用的体验. 而且,针对于相同的HTML页面来说TABLE布局,不利于搜索引擎的爬虫爬行下载页面.从而造 ...
 - String及其常用API
			
String 类代表字符串.Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现. 字符串是常量:它们的值在创建之后不能更改.字符串缓冲区支持可变的字符串.因 ...
 - .NET Framework 各版本区别(简介)
			
本文通过在网络资料整理而得. .NET Framework1.1 1.自带了对mobile asp.net控件的支持.(在1.0版本是以附加功能实现) 2.加入了ASP.NET应用程序的代码安全访问功 ...
 - css  层叠式样式表
			
内联样式:样式优先级最高的 <div style="width:100px;height:100px;"></div> style=“” 用冒号和分号 wi ...
 - Hadoop2.7.3+Spark2.1.0完全分布式集群搭建过程
			
1.选取三台服务器(CentOS系统64位) 114.55.246.88 主节点 114.55.246.77 从节点 114.55.246.93 从节点 之后的操作如果是用普通用户操作的话也必须知道r ...
 - java学习笔记----运算符
			
一.算数运算符 特别说明: 加 ,减 ,乘 ,除 与数学运算一致 取余符号看被除数 自加(减)运算:++a,--a;先做自加(自减)运算在做其他运算 a++,a--;先做其他运算在做自加(自减)运算 ...
 - keystone无法查看catalog并且用户无法申请令牌的解决方案
			
在运行openstack catalog list之后提示: Only an authorized user may issue a new token. #只有授权用户才能申请token opens ...
 - iOS回顾笔记(09) -- Cell的添加、删除、更新、批量操作
			
iOS回顾笔记(09) -- Cell的添加.删除.更新.批量操作 项目中经常有对UITableViewCell做各种操作的需求: 添加一个新的cell 删除某行cell 刷新cell上某行数据(如修 ...
 - 老李教你性能测试监控工具nmon
			
老李教你性能测试监控工具nmon loadrunner的某些性能监控器不够强大,这就需要我们利用更好的工具进行监控,在项目中我们会用nmon工具作为辅助性能监控的工具,帮助我们进行性能分析,pop ...
 - 老李推荐:第6章7节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览-注入按键事件实例
			
老李推荐:第6章7节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览-注入按键事件实例 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜 ...