题面

传送门

思路

$LCT$

我们发现,这个1操作,好像非常像$LCT$里面的$Access$啊~

那么我们尝试把$Access$操作魔改成本题中的涂色

我们令$LCT$中的每一个$splay$链代表同一种颜色的一条链,那么$Access(u)$就相当于把这一段变成同一种颜色

注意这个东西能成立,是因为每次涂上的都是新的一种颜色(所以如果有$m$种颜色,每次涂其中一种,可能重复的之类的就不能这么做了)

线段树

接下来我们解决询问的问题:什么结构能维护链上信息和子树信息(同时)?当然是线段树了~

我们考虑开一棵以$dfs$序为下标的线段树,线段树的每个叶节点保存这个节点到根的路径权值,其他节点维护对应区间的最大值

这样,询问三就变成了区间求$max$,询问二则可以化成$w[u]+w[v]-2*w[lca]+1$这样的形式($w[u]$表示$u$到根路径上的权值)(这个东西不管颜色怎么分布,一定是对的,证明很容易,可以自己想想)

但是这样之后,我们在修改一的时候,怎么修改线段树上的值呢?

维护线段树

我们发现,在修改的过程中,每一次我们从当前$splay$连向上面的$splay$时,会把一条虚边变成重边、一条重边变成虚边

那么,原来重边下的这棵子树,因为它上面的东西变成了新的颜色,而上面的东西本来是和它一个颜色的,所以重边的这棵子树中所有节点的权值要+1

而对于原来虚边下面的这棵子树来说,它上面的东西本来和它不是一个颜色的,现在是同一个颜色了,所以虚边的子树中所有节点的权值要-1

这样,我们只要在$Access$的时候,同时维护线段树的权值就可以了

总结

本题从与$Access$相似的修改方式开始,切入点是$LCT$,然后加入了线段树维护,并且确定了在$Access$操作的同时修改线段树的值

总时间复杂度为均摊$O(nlog^2n)$

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<cmath>
#define ll long long
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') flag=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
int n,Q,first[100010],cnte,dep[100010],st[100010][20],dfn[100010],lim[100010],back[100010],cntn;
int fa[100010];
struct edge{
int to,next;
}e[200010];
inline void add(int u,int v){
e[++cnte]=(edge){v,first[u]};first[u]=cnte;
e[++cnte]=(edge){u,first[v]};first[v]=cnte;
}
void dfs(int u,int f){
int i,v;dep[u]=dep[f]+1;st[u][0]=f;fa[u]=f;//这里把LCT的fa数组预处理好(此时没有边,都是虚边)
dfn[u]=++cntn;back[cntn]=u;
for(i=first[u];~i;i=e[i].next){
v=e[i].to;if(v==f) continue;
dfs(v,u);
}
lim[u]=cntn;
}
void ST(){
for(int j=1;j<=19;j++){
for(int i=1;i<=n;i++) st[i][j]=st[st[i][j-1]][j-1];
}
}
int lca(int l,int r){
int i;
if(dep[l]>dep[r]) swap(l,r);
for(i=19;i>=0;i--) if(dep[st[r][i]]>=dep[l]) r=st[r][i];
if(l==r) return l;
for(i=19;i>=0;i--){
if(st[r][i]!=st[l][i]){
l=st[l][i];
r=st[r][i];
}
}
return st[l][0];
}
//segment tree
int a[400010],lazy[400010];
void update(int num){
a[num]=max(a[num<<1],a[num<<1|1]);
}
void push(int l,int r,int num){
if(l==r||!lazy[num]) return;
a[num<<1]+=lazy[num];a[num<<1|1]+=lazy[num];
lazy[num<<1]+=lazy[num];lazy[num<<1|1]+=lazy[num];
lazy[num]=0;
}
void build(int l,int r,int num){
if(l==r){a[num]=dep[back[l]];return;}
int mid=(l+r)>>1;
build(l,mid,num<<1);build(mid+1,r,num<<1|1);
update(num);
}
void change(int l,int r,int ql,int qr,int num,int ch){
push(l,r,num);
if(l>=ql&&r<=qr){a[num]+=ch;lazy[num]+=ch;return;}
int mid=(l+r)>>1;
if(mid>=ql) change(l,mid,ql,qr,num<<1,ch);
if(mid<qr) change(mid+1,r,ql,qr,num<<1|1,ch);
update(num);
}
int query(int l,int r,int ql,int qr,int num){
push(l,r,num);
if(l>=ql&&r<=qr) return a[num];
int mid=(l+r)>>1,re=-1e9;
if(mid>=ql) re=max(re,query(l,mid,ql,qr,num<<1));
if(mid<qr) re=max(re,query(mid+1,r,ql,qr,num<<1|1));
return re;
}
//link cut tree
int ch[100010][2]={0},rt[100010];
int get(int pos){return ch[fa[pos]][1]==pos;}
void rotate(int x){
int f=fa[x],ff=fa[f],son=get(x);
ch[f][son]=ch[x][son^1];
if(ch[f][son]) fa[ch[f][son]]=f;
fa[f]=x;ch[x][son^1]=f;
fa[x]=ff;
if(rt[f]) rt[x]=1,rt[f]=0;
else ch[ff][ch[ff][1]==f]=x;
}
void splay(int pos){
if(rt[pos]) return;
for(int f;!rt[pos];rotate(pos)){
if(!rt[f=fa[pos]])
rotate((get(f)==get(pos))?f:pos);
}
}
int pre(int pos){
while(ch[pos][0]) pos=ch[pos][0];
return pos;
}
void access(int pos){
for(int tmp=0,tt;pos;tmp=pos,pos=fa[pos]){
splay(pos);
if(ch[pos][1]){//重边变虚边,+1
tt=pre(ch[pos][1]);
change(1,n,dfn[tt],lim[tt],1,1);
}
rt[ch[pos][1]]=1;ch[pos][1]=tmp;rt[tmp]=0;
if(tmp){//虚边变重边,-1
tt=pre(tmp);
change(1,n,dfn[tt],lim[tt],1,-1);
}
}
}
int main(){
memset(first,-1,sizeof(first));
n=read();Q=read();int i,t1,t2,t3,f;
for(i=1;i<n;i++){
t1=read();t2=read();
add(t1,t2);
}
dfs(1,0);ST();build(1,n,1);
for(i=1;i<=n;i++) rt[i]=1;
while(Q--){
t1=read();
if(t1==1){
t2=read();access(t2);
}
if(t1==2){
t2=read();t3=read();
f=lca(t2,t3);
printf("%d\n",query(1,n,dfn[t2],dfn[t2],1)+query(1,n,dfn[t3],dfn[t3],1)-2*query(1,n,dfn[f],dfn[f],1)+1);
}
if(t1==3){
t2=read();
printf("%d\n",query(1,n,dfn[t2],lim[t2],1));
}
}
}

[SDOI2017][bzoj4817] 树点涂色 [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. BZOJ4817[Sdoi2017]树点涂色——LCT+线段树

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

  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. 在线代码编辑器 Codemirror 的轻量级 React 组件

    代码编辑器 CodeMirror 的轻量级 React 组件 demo @uiw-react.github.io/react-codemirror/ 特性:

  2. Spring框架基础2

    Spring框架基础2 测试Spring的AOP思想和注解的使用 导包(在前面的基础上添加) SpringAOP名词解释 AOP编程思想:横向重复代码,纵向抽取:就是说多个地方重复的代码可以抽取出来公 ...

  3. Mysql5.7.25在windows下安装

    在网上看到了很多安装方法,也试了很多,md,网上资源多了也是有各种坑,这里只说在windows下安装mysql5.7.25 一.下载安装包 链接:https://dev.mysql.com/downl ...

  4. scrapy--ipproxy

    不要急于求成,你只要做的是比昨天的你更优秀一点 --匿名 今天给大家讲一下--IpProxy,由于从"http://www.xicidaili.com/nn"爬取,以下是我转载的博 ...

  5. Elasticsearch和Head插件安装

    环境: CentOS7  Elasticsearch-6.3.2 JDK8 准备: JDK8 下载地址:http://www.oracle.com/technetwork/java/javase/do ...

  6. Python元组,列表,字典,集合

    1.元组 元组是有序的,只有index和count两种方法,一看到元组,就提醒是不可更改的 names = ('wll', 'ly', 'jxx', 'syq') (1)index方法 print(n ...

  7. POJ:2739-Sum of Consecutive Prime Numbers(尺取)

    Sum of Consecutive Prime Numbers Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 27853 Ac ...

  8. POJ:1703-Find them, Catch them(并查集好题)(种类并查集)

    Find them, Catch them Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 49867 Accepted: 153 ...

  9. [Bzoj1034][ZJOI2008]泡泡堂BNB(贪心)

    Description 题目链接 Solution 这题就是一个贪心, 如果最弱的能赢对方最弱的就赢 否则最强的能赢对面最强的就赢 否则最弱的换对面最强 Code #include <cstdi ...

  10. [Bzoj4289]PA2012 Tax(Dijkstra+技巧建图)

    Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边 ...