LCT好题

首先我们考虑实际询问的是什么:

从LCT的角度考虑,如果我们认为一开始树上每一条边都是虚边,把一次涂色看作一次access操作,那么询问的实际就是两个节点间的虚边数量+1和子树中的最大虚边数量!

这种问题显然树上容斥,如果设$dis_{i}$表示$i$到根节点需要经过多少虚边,那么答案显然是$dis_{x}+dis_{y}-2dis_{LCA(x,y)}+1$

那么我们实际只是在维护这个$dis_{i}$

怎么维护?

我们注意到,虚实边的转化对应着access操作,因此我们肯定考虑access中进行维护

注意到在每次access的时候,实际对应着三步操作:

第一步:将节点旋转到根

第二步:将节点与右子树之间的边由实边断为虚边

第三步:将节点与原先节点之间的边由虚边变为实边

那么实边变为虚边对应着虚边数量增加,虚边变为实边对应着虚边数量减少

由于这棵树的形态不变,我们考虑直接用线段树维护dfs序,这样就支持了单点查询$dis$和查询子树中最大的$dis$

在修改的时候,考虑到每次access操作的过程,每一次虚实边的变化实际影响的是一棵子树

而这棵子树的根就是在splay上右子树中最靠左的那个点!

因此我们找到这个根,更新即可,区间修改,单点查询+区间查询即可

贴代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define rt1 rt<<1
#define rt2 (rt<<1)|1
using namespace std;
struct Seg_tree
{
int lazy,maxv;
}tree[400005];
struct Edge
{
int nxt,to;
}edge[200005];
int head[100005];
int ch[100005][2];
int f[100005];
int fa[100005][25];
int dep[100005];
int fl[100005];
int inr[100005],our[100005],onum[100005];
int cnt=1,tot;
int n,m;
void add(int l,int r)
{
edge[cnt].nxt=head[l];
edge[cnt].to=r;
head[l]=cnt++;
}
void dfs(int x,int fx)
{
dep[x]=dep[fx]+1,fa[x][0]=f[x]=fx,inr[x]=++tot,onum[tot]=x;
for(int i=1;i<=20;i++)fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(to==fx)continue;
dfs(to,x);
}
our[x]=tot;
}
int LCA(int x,int y)
{
if(dep[x]>dep[y])swap(x,y);
for(int i=20;i>=0;i--)if(dep[fa[y][i]]>=dep[x])y=fa[y][i];
if(x==y)return x;
int ret;
for(int i=20;i>=0;i--)
{
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
else ret=fa[x][i];
}
return ret;
}
void buildtree(int rt,int l,int r)
{
if(l==r){tree[rt].maxv=dep[onum[l]];return;}
int mid=(l+r)>>1;
buildtree(rt1,l,mid),buildtree(rt2,mid+1,r);
tree[rt].maxv=max(tree[rt1].maxv,tree[rt2].maxv);
}
void down(int rt)
{
tree[rt1].lazy+=tree[rt].lazy,tree[rt1].maxv+=tree[rt].lazy;
tree[rt2].lazy+=tree[rt].lazy,tree[rt2].maxv+=tree[rt].lazy;
tree[rt].lazy=0;
}
void update(int rt,int l,int r,int lq,int rq,int v)
{
if(l>=lq&&r<=rq){tree[rt].lazy+=v;tree[rt].maxv+=v;return;}
int mid=(l+r)>>1;
if(tree[rt].lazy)down(rt);
if(lq<=mid)update(rt1,l,mid,lq,rq,v);
if(rq>mid)update(rt2,mid+1,r,lq,rq,v);
tree[rt].maxv=max(tree[rt1].maxv,tree[rt2].maxv);
}
int query(int rt,int l,int r,int lq,int rq)
{
if(l>=lq&&r<=rq)return tree[rt].maxv;
int mid=(l+r)>>1;
if(tree[rt].lazy)down(rt);
int ret=0;
if(lq<=mid)ret=max(ret,query(rt1,l,mid,lq,rq));
if(rq>mid)ret=max(ret,query(rt2,mid+1,r,lq,rq));
return ret;
}
bool be_root(int x)
{
if(ch[f[x]][0]==x||ch[f[x]][1]==x)return 0;
return 1;
}
void pushdown(int x)
{
if(fl[x])
{
swap(ch[ch[x][0]][0],ch[ch[x][0]][1]);
swap(ch[ch[x][1]][0],ch[ch[x][1]][1]);
fl[ch[x][0]]^=1,fl[ch[x][1]]^=1;
fl[x]=0;
}
}
void repush(int x)
{
if(!be_root(x))repush(f[x]);
pushdown(x);
}
void rotate(int x)
{
int y=f[x],z=f[y],k=(ch[y][1]==x);
if(!be_root(y))ch[z][ch[z][1]==y]=x;
f[x]=z;
ch[y][k]=ch[x][!k],f[ch[x][!k]]=y;
ch[x][!k]=y,f[y]=x;
}
void splay(int x)
{
repush(x);
while(!be_root(x))
{
int y=f[x],z=f[y];
if(!be_root(y))
{
if((ch[y][1]==x)^(ch[z][1]==y))rotate(x);
else rotate(y);
}
rotate(x);
}
}
int get_root(int x)
{
while(ch[x][0])x=ch[x][0];
return x;
}
void access(int x)
{
int y=0;
while(x)
{
splay(x);
if(ch[x][1])
{
int rt=get_root(ch[x][1]);
update(1,1,n,inr[rt],our[rt],1);
}
ch[x][1]=y;
if(y)
{
int rt=get_root(y);
update(1,1,n,inr[rt],our[rt],-1);
}
y=x,x=f[x];
}
}
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main()
{
n=read(),m=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
add(x,y),add(y,x);
}
dfs(1,0),buildtree(1,1,n);
while(m--)
{
int typ=read();
if(typ==1)
{
int x=read();
access(x);
}else if(typ==2)
{
int x=read(),y=read(),fa=LCA(x,y);
int s1=query(1,1,n,inr[x],inr[x]),s2=query(1,1,n,inr[y],inr[y]),s3=query(1,1,n,inr[fa],inr[fa]);
printf("%d\n",s1+s2-2*s3+1);
}else
{
int x=read();
printf("%d\n",query(1,1,n,inr[x],our[x]));
}
}
return 0;
}

bzoj 4817的更多相关文章

  1. AC日记——[SDOI2017]树点涂色 bzoj 4817

    4817 思路: 跪烂大佬 代码: #include <bits/stdc++.h> using namespace std; #define maxn 500005 struct Tre ...

  2. bzoj 4817: [Sdoi2017]树点涂色

    Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...

  3. [BZOJ 4817] [SDOI 2017] 树点涂色

    Description Bob有一棵 \(n\) 个点的有根树,其中 \(1\) 号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点(包括起点和终点 ...

  4. BZOJ.4817.[SDOI2017]树点涂色(LCT DFS序 线段树)

    题目链接 操作\(1.2\)裸树剖,但是操作\(3\)每个点的答案\(val\)很不好维护.. 如果我们把同种颜色的点划分到同一连通块中,那么向根染色的过程就是Access()! 最初所有点间都是虚边 ...

  5. 【刷题】BZOJ 4817 [Sdoi2017]树点涂色

    Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...

  6. BZOJ 4817: [Sdoi2017]树点涂色(LCT+树剖+线段树)

    题目描述 Bob有一棵 nn 个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. Bob ...

  7. bzoj 4817: [Sdoi2017]树点涂色 LCT+树链剖分+线段树

    题目: Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. Bob可能会进 ...

  8. BZOJ 4817 [Sdoi2017]树点涂色 ——LCT 线段树

    同BZOJ3779. SDOI出原题,还是弱化版的. 吃枣药丸 #include <map> #include <cmath> #include <queue> # ...

  9. bzoj 4817: [Sdoi2017]树点涂色【树链剖分+LCT】

    非常妙的一道题. 首先对于操作一"把点x到根节点的路径上所有的点染上一种没有用过的新颜色",长得是不是有点像LCT中的access操作?进而发现,如果把同一颜色的点连起来作为LCT ...

  10. BZOJ 4817: [Sdoi2017]树点涂色 LCT+Access的性质+DFS序+线段树

    Code: #include<bits/stdc++.h> #define maxn 200003 #define inf -1000000 using namespace std; vo ...

随机推荐

  1. kumquat

    今天准备做个解释型编程语言,名字就叫kumquat(金桔)因为我刚刚喝了口金桔柠檬茶,挺甜的 用python写把

  2. 17.SQLite数据库存储

    Android系统内置一个SQLite数据库,SQLite是一款轻量级的关系型数据库,它的运算速度非常快,占用资源很少,通常只需要几百K的内存就足够了. SQLite不仅支持标准的SQL语法,还遵循了 ...

  3. (0514)芯王国-志锐-Sd卡高速控制-AXI验证

    (1)commit (2)core  (3)generate (4)struct  结构体 (5)

  4. PyCharm的安装使用

    一.安装 1.进入官网点击下载 2.打开文件夹 3.点击next 4.选择安装路径 5.勾选创建桌面图标选项,点击next 6.点击安装 二.使用 1.import pycharm setting是指 ...

  5. <string> <cstring> <string.h>

    <string>是C++标准库头文件,包含了拟容器class std::string的声明(不过class string事实上只是basic_string<char>的type ...

  6. mysql去重保留1条记录

    delete from `wuye` where wuye_id in ( select * from ( select wuye_id from `wuye` where wuye_name in ...

  7. c/c++工程中为什么仅仅main.cpp引用其他源文件的头文件不够,源文件还要引用自身的头文件?

    原博客链接: https://blog.csdn.net/khwkhwkhw/article/details/49798985?utm_source=app&from=timeline 引言: ...

  8. PCB Layout之EMMC_Flash走线总结@@@

    PCB Layout之EMMC_Flash走线总结 1,数据线DATA[0-7]走线要(基本)等长(含芯片内部线长),线要短,线间距控制3W原则,参考面要完整(参考面下面最好不要走其它高速信号线),阻 ...

  9. 使用myBadboy(python自主开发工具)启动谷歌浏览器并自动录制jmeter脚本

    一.源代码下载 https://gitee.com/rmtic/mybadboy 说明:因现有的录制方法有不能定制等不足之处,所以自力更生,自动生成对应jmeter脚本,减少维护成本 二.操作说明 1 ...

  10. 配置全局路由表和VRF路由表之间的路由泄漏

    1.拓扑图 2.R1配置 R1#sho run Building configuration... Current configuration : 1360 bytes ! upgrade fpd a ...