题目描述

Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
1 x:
把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:
求x到y的路径的权值。
3 x
在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。
Bob一共会进行m次操作

输入

第一行两个数n,m。
接下来n-1行,每行两个数a,b,表示a与b之间有一条边。
接下来m行,表示操作,格式见题目描述
1<=n,m<=100000

输出

每当出现2,3操作,输出一行。
如果是2操作,输出一个数表示路径的权值
如果是3操作,输出一个数表示权值的最大值

样例输入

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

样例输出

3
4
2
2
 
我们将连续相同颜色的一条链看成一条重链,可以发现修改操作其实就是$LCT$里的$access$操作。
那么每个节点到根的权值就是这个点到根路径上的重链数。
考虑用线段树维护出每个点到根的权值,每次修改时假设路径上$x->fa$的边是轻边,$fa$的重儿子是$son$,那么就将$son$子树中所有点的答案$+1$,$x$子树中所有点答案$-1$,然后将$x$变为$fa$的重儿子。在$access$时完成子树修改操作即可。
对于查询$x$到$y$的路径权值,就是$v[x]+v[y]-2v[lca]+1$。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int c[100010][2];
int fa[100010];
int tag[400010];
int f[100010][18];
int dep[100010];
int mx[400010];
int dfn;
int tot;
int x,y;
int n,m;
int opt;
int head[100010];
int next[200010];
int to[200010];
int q[100010];
int s[100010];
int t[100010];
void add(int x,int y)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void pushup(int rt)
{
mx[rt]=max(mx[rt<<1],mx[rt<<1|1]);
}
void pushdown(int rt)
{
if(tag[rt])
{
tag[rt<<1]+=tag[rt];
tag[rt<<1|1]+=tag[rt];
mx[rt<<1]+=tag[rt];
mx[rt<<1|1]+=tag[rt];
tag[rt]=0;
}
}
void build(int rt,int l,int r)
{
if(l==r)
{
mx[rt]=dep[q[l]];
return ;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void change(int rt,int l,int r,int L,int R,int v)
{
if(L<=l&&r<=R)
{
tag[rt]+=v;
mx[rt]+=v;
return ;
}
pushdown(rt);
int mid=(l+r)>>1;
if(L<=mid)
{
change(rt<<1,l,mid,L,R,v);
}
if(R>mid)
{
change(rt<<1|1,mid+1,r,L,R,v);
}
pushup(rt);
}
int query(int rt,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
return mx[rt];
}
pushdown(rt);
int mid=(l+r)>>1;
int res=0;
if(L<=mid)
{
res=max(res,query(rt<<1,l,mid,L,R));
}
if(R>mid)
{
res=max(res,query(rt<<1|1,mid+1,r,L,R));
}
return res;
}
int ask(int rt,int l,int r,int k)
{
if(l==r)
{
return mx[rt];
}
pushdown(rt);
int mid=(l+r)>>1;
if(k<=mid)
{
return ask(rt<<1,l,mid,k);
}
else
{
return ask(rt<<1|1,mid+1,r,k);
}
}
bool is_root(int rt)
{
return rt!=c[fa[rt]][0]&&rt!=c[fa[rt]][1];
}
bool get(int rt)
{
return rt==c[fa[rt]][1];
}
void rotate(int rt)
{
int x=fa[rt];
int y=fa[x];
int k=get(rt);
if(!is_root(x))
{
c[y][get(x)]=rt;
}
c[x][k]=c[rt][k^1];
fa[c[rt][k^1]]=x;
c[rt][k^1]=x;
fa[x]=rt;
fa[rt]=y;
}
void splay(int rt)
{
for(int x;!is_root(rt);rotate(rt))
{
if(!is_root(x=fa[rt]))
{
rotate(get(x)==get(rt)?x:rt);
}
}
}
void link(int x,int y)
{
fa[x]=y;
}
int find(int rt)
{
while(c[rt][0])
{
rt=c[rt][0];
}
return rt;
}
void access(int rt)
{
for(int x=0;rt;x=rt,rt=fa[rt])
{
splay(rt);
if(x)
{
int son=find(x);
change(1,1,n,s[son],t[son],-1);
}
if(c[rt][1])
{
int son=find(c[rt][1]);
change(1,1,n,s[son],t[son],1);
}
c[rt][1]=x;
}
}
void dfs(int x)
{
s[x]=++dfn;
q[dfn]=x;
for(int i=1;i<=17;i++)
{
f[x][i]=f[f[x][i-1]][i-1];
}
for(int i=head[x];i;i=next[i])
{
if(to[i]!=f[x][0])
{
f[to[i]][0]=x;
link(to[i],x);
dep[to[i]]=dep[x]+1;
dfs(to[i]);
}
}
t[x]=dfn;
}
int lca(int x,int y)
{
if(dep[x]<dep[y])
{
swap(x,y);
}
int d=dep[x]-dep[y];
for(int i=0;i<=17;i++)
{
if(d&(1<<i))
{
x=f[x][i];
}
}
if(x==y)
{
return x;
}
for(int i=17;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
return f[x][0];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dep[1]=1;
dfs(1);
build(1,1,n);
while(m--)
{
scanf("%d",&opt);
if(opt==1)
{
scanf("%d",&x);
access(x);
}
else if(opt==2)
{
scanf("%d%d",&x,&y);
int anc=lca(x,y);
int ans=ask(1,1,n,s[x])+ask(1,1,n,s[y])-2*ask(1,1,n,s[anc])+1;
printf("%d\n",ans);
}
else
{
scanf("%d",&x);
printf("%d\n",query(1,1,n,s[x],t[x]));
}
}
}

BZOJ4817[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]树点涂色 [lct 线段树]

    [Sdoi2017]树点涂色 题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值 考场发现这个信息是可减的,但是没想到lct 特意设计成lct的形式! 如何求颜色数? ...

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

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

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

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

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

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

  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. vue 常用语法糖

    //来自 https://www.cnblogs.com/lhl66/p/8021730.html 侵删 el:element 需要获取的元素,一定是HTML中的根容器元素 data:用于数据的存储 ...

  2. 2018年12月8日广州.NET微软技术俱乐部活动总结

    吕毅写了一篇活动总结,写得很好!原文地址是:https://blog.walterlv.com/post/december-event-microsoft-technology-salon.html ...

  3. zabbix3.4 监控mysql 数据库连接数

    zabbix3.4 监控mysql 数据库连接数具体监控配置待定,近期即将发布!

  4. Thinkphp5整合微信扫码支付开发实例

    ThinkPHP框架是比较多人用的,曾经做过的一个Thinkphp5整合微信扫码支付开发实例,分享出来大家一起学习 打开首页生成订单,并显示支付二维码 public function index() ...

  5. Windows编译OpenCV4Android解决undefined reference to std错误

    注意OpenCV 4.0.1 解决了这个问题请直接下载OpenCV 4.0.1 但是OpenCV 4.0.1作为模块导入Android Studio会有找不到R.styleable的问题 OpenCV ...

  6. 精简你的 docker 镜像

    精简你的 docker 镜像 Intro 现在 docker 的使用越来越普遍,今天来谈一下如何精简你的 docker 镜像 为什么要精简 docker 首先来说说为什么要精简 docker 镜像,减 ...

  7. js计算剩余分钟

    // 剩余时间提醒 function checkTime() { if (timeCompare()) { document.getElementById('distanceDeadline').in ...

  8. AES 加密与解密

    using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Securit ...

  9. 【原】Java学习笔记008 - 方法(函数)

    package cn.temptation; public class Sample01 { public static void main(String[] args) { // 方法/函数 Met ...

  10. python3 正则表达式点星问号(.*?)能不能匹配换行符?不能的话应该怎么写

    python3的re模块使用过程中,正则的书写遇到了一些问题,就是使用.*?能不能匹配到换行符的问题. 答案是不能. 如果在匹配过程中遇到了也没关系,加上这个语句就好: \s+