【BZOJ4817】树点涂色(LCT,线段树,树链剖分)
【BZOJ4817】树点涂色(LCT,线段树,树链剖分)
题面
Description
Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
1 x:
把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:
求x到y的路径的权值。
3 x y:
在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
Bob一共会进行m次操作
Input
第一行两个数n,m。
接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
接下来m行,表示操作,格式见题目描述
1<=n,m<=100000
Output
每当出现2,3操作,输出一行。
如果是2操作,输出一个数表示路径的权值
如果是3操作,输出一个数表示权值的最大值
Sample Input
5 6
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
3
4
2
2
题解
很有趣的一道题
先不考虑第一个操作
假设我们知道每个点到达根节点的答案\(f(i)\)
那么,第二个询问就是平时的\(u+v-2lca\)的操作
也就是\(f(u)+f(v)-2f(lca)+1\)。
加一的原因是\(lca\)的颜色被多减了一次
第三个操作?直接求子树最大值
转换成\(dfs\)序上的区间最大值
很显然线段树
初始状态下,线段树的权值就是树的深度\(dep\)
好的,现在看第一个操作
处理到根的链?这个操作迷之熟悉。
十分类似于\(LCT\)的\(access\),也就是将\(x\)到根节点变为重链
这个操作呢?似乎是一样的。
那么考虑一下在\(access\)的操作中对于答案的影响
如果断开了右儿子的链,意味着右儿子需要额外的多跳一次
给右儿子所在的子树的答案加一
而接上来的右子树显然会少跳一次
那么给新的右子树的答案减一
这样所有的问题就解决完了
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 111111
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Node{int ch[2],ff;}t[MAX];
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1,n,m;
int fa[MAX],dfn[MAX],low[MAX],tim,dep[MAX];
int size[MAX],hson[MAX],top[MAX],ln[MAX];
void dfs1(int u,int ff)
{
fa[u]=ff;dep[u]=dep[ff]+1;size[u]=1;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==ff)continue;
dfs1(v,u);size[u]+=size[v];
if(size[v]>size[hson[u]])hson[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;dfn[u]=++tim;ln[tim]=u;
if(hson[u])dfs2(hson[u],tp);
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==hson[u]||v==fa[u])continue;
dfs2(v,v);
}
low[u]=tim;
}
int LCA(int u,int v)
{
while(top[u]!=top[v])
dep[top[u]]<dep[top[v]]?v=fa[top[v]]:u=fa[top[u]];
return dep[u]<dep[v]?u:v;
}
struct SegNode{int v,tg;}T[MAX<<2];
void Build(int now,int l,int r)
{
if(l==r){T[now].v=dep[ln[l]];return;}
int mid=(l+r)>>1;
Build(lson,l,mid);Build(rson,mid+1,r);
T[now].v=max(T[lson].v,T[rson].v);
}
void puttag(int now,int w){T[now].tg+=w;T[now].v+=w;}
void pushdown(int now){puttag(lson,T[now].tg);puttag(rson,T[now].tg);T[now].tg=0;}
void Modify(int now,int l,int r,int L,int R,int w)
{
if(L<=l&&r<=R){puttag(now,w);return;}
int mid=(l+r)>>1;pushdown(now);
if(L<=mid)Modify(lson,l,mid,L,R,w);
if(R>mid)Modify(rson,mid+1,r,L,R,w);
T[now].v=max(T[lson].v,T[rson].v);
}
int QueryV(int now,int l,int r,int p)
{
if(l==r)return T[now].v;
int mid=(l+r)>>1;pushdown(now);
if(p<=mid)return QueryV(lson,l,mid,p);
else return QueryV(rson,mid+1,r,p);
}
int QueryMx(int now,int l,int r,int L,int R)
{
if(L<=l&&r<=R)return T[now].v;
int mid=(l+r)>>1,ret=0;pushdown(now);
if(L<=mid)ret=max(ret,QueryMx(lson,l,mid,L,R));
if(R>mid)ret=max(ret,QueryMx(rson,mid+1,r,L,R));
return ret;
}
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
bool isroot(int x){return t[t[x].ff].ch[0]!=x&&t[t[x].ff].ch[1]!=x;}
void rotate(int x)
{
int y=t[x].ff,z=t[y].ff;
int k=t[y].ch[1]==x;
if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;
t[x].ch[k^1]=y;t[y].ff=x;
}
void Splay(int x)
{
while(!isroot(x))
{
int y=t[x].ff,z=t[y].ff;
if(!isroot(y))
(t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
rotate(x);
}
}
int findroot(int x){while(t[x].ch[0])x=t[x].ch[0];return x;}
void access(int x)
{
for(int y=0;x;y=x,x=t[x].ff)
{
Splay(x);
if(t[x].ch[1])
{
int u=findroot(t[x].ch[1]);
Modify(1,1,n,dfn[u],low[u],1);
}
t[x].ch[1]=y;
if(t[x].ch[1])
{
int u=findroot(t[x].ch[1]);
Modify(1,1,n,dfn[u],low[u],-1);
}
}
}
int main()
{
n=read();m=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read();
Add(u,v);Add(v,u);
}
dfs1(1,0);dfs2(1,1);
for(int i=2;i<=n;++i)t[i].ff=fa[i];
Build(1,1,n);
while(m--)
{
int opt=read();
if(opt==1)access(read());
else if(opt==2)
{
int u=read(),v=read(),lca=LCA(u,v);
printf("%d\n",QueryV(1,1,n,dfn[u])+QueryV(1,1,n,dfn[v])-2*QueryV(1,1,n,dfn[lca])+1);
}
else
{
int u=read();
printf("%d\n",QueryMx(1,1,n,dfn[u],low[u]));
}
}
return 0;
}
【BZOJ4817】树点涂色(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]树点涂色 [lct 线段树]
[Sdoi2017]树点涂色 题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值 考场发现这个信息是可减的,但是没想到lct 特意设计成lct的形式! 如何求颜色数? ...
- [SDOI2017][bzoj4817] 树点涂色 [LCT+线段树]
题面 传送门 思路 $LCT$ 我们发现,这个1操作,好像非常像$LCT$里面的$Access$啊~ 那么我们尝试把$Access$操作魔改成本题中的涂色 我们令$LCT$中的每一个$splay$链代 ...
- 【bzoj4817】树点涂色 LCT+线段树+dfs序
Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...
- 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 ...
- 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\)(画图理解).剩下的操作 ...
随机推荐
- 查看Oracle数据库表空间大小(空闲、已使用),是否要增加表空间的数据文件
查看Oracle数据库表空间大小(空闲.已使用),是否要增加表空间的数据文件 1.查看表空间已经使用的百分比 Sql代码 select a.tablespace_name,a.bytes/1024/1 ...
- Qt-QMl-自定义自己想要的TabView
上效果图 上实现源码,这里的代码都是来自Qt官方源码修改其中某一行内容 /* 作者:张建伟 时间:2018年4月8日 简述:自定义TabView,主要实现Tab和实现内容重叠,不在占用独立空间 该文件 ...
- Selenide 阶段性总结介绍(UI自动化测试工具)
今天给大家介绍一个比较新的UI自动化测试工具-- Selenide.确实是比较新的,国内应该还没有多少人用它.在百度和google上你只能搜到一个中文帖子简单介绍了一下.如果你想用这个工具,不可避免的 ...
- sqlserver(2012)清理tempdb
当数据库运行时间长了之后,tempdb变得特别大,几十G,受不了啊:当然我们知道重启 SQL Server服务的话,tempdb数据库会自动重新创建的,从而使 tempdb 回归到初始大小.但是这是生 ...
- Vue 项目在其他电脑 npm run dev 运行报错的解决方法
一个 Vue 项目从一台电脑上传到 github 上之后,再另外一台电脑上 git clone .并使用 npm run dev 或 npm run start 发生以下报错的解决方法. 报错原因 ...
- 1035 Password (20 分)(字符串)
注意下单复数 #include<bits/stdc++.h> using namespace std; pair<string,string>pa; int main() { ...
- 个人第十一周PSP
11.24 --11.30本周例行报告 1.PSP(personal software process )个人软件过程. 类型 任务 开始时间 结束时间 中断时间 实际用 ...
- C++ Primer Plus学习:第八章
C++入门第八章:函数探幽 本章将介绍C++语言区别于C语言的新特性.包括内联函数.按引用传递变量.默认的参数值.函数重载以及函数模板. 1 C++内联函数 内联函数是C++为提高程序运行速度所做的一 ...
- zuoyeQAQ
public class StringAPIDemo { /** * @param args */ public static void main(String[] args) { // TODO A ...
- ssh: Could not resolve hostname问题终于解决了?
1.如果系统为64位,无法启动启动hdfs: ./sbin/start-dfs.sh.并有以下错误: sed: -e expression #1, char 6: unknown option to ...