Description

Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同。定义一条路
径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。Bob可能会进行这几种操作:
1 x:
把点x到根节点的路径上所有的点染上一种没有用过的新颜色。
2 x y:
求x到y的路径的权值。
3 x
在以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

解题思路:

LCT好题access构造。

将第一个操作视为access操作并更新答案。

那么开始时视为没有轻重链。

access过程中若发生轻重链转化时将子树答案都加1,并撤销上一节点操作。

这样就可以在每一个节点上维护到根的权值和。

第三问直接解决。

第二问呢,发现合并两条链的代价就是两个链单独的代价-2*lca代价+1(因为lca节点需要考虑)

子树修改普通Dfs就好了。

代码:

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define lll tr[spc].ch[0]
#define rrr tr[spc].ch[1]
#define ls ch[0]
#define rs ch[1]
typedef long long lnt;
const int N=;
struct seg_trnt{
int lzt;
int maxval;
}ter[N<<];
struct spl_trnt{
int ch[];
int fa;
int lzt;
bool anc;
}tr[N];
struct pnt{
int hd;
int dp;
int ind;
int oud;
int fa[];
}p[N];
struct ent{
int twd;
int lst;
}e[N<<];
int n,m;
int cnt;
int dfn;
bool sta=true;
int pos[N];
void pushup(int spc)
{
ter[spc].maxval=std::max(ter[spc<<].maxval,ter[spc<<|].maxval);
return ;
}
void ppushdown(int spc)
{
if(ter[spc].lzt)
{
ter[spc<<].maxval+=ter[spc].lzt;
ter[spc<<|].maxval+=ter[spc].lzt;
ter[spc<<].lzt+=ter[spc].lzt;
ter[spc<<|].lzt+=ter[spc].lzt;
ter[spc].lzt=;
}
return ;
}
void update(int l,int r,int ll,int rr,int spc,int v)
{
if(ll>r||l>rr)
return ;
if(ll<=l&&r<=rr)
{
ter[spc].maxval+=v;
ter[spc].lzt+=v;
return ;
}
ppushdown(spc);
int mid=(l+r)>>;
update(l,mid,ll,rr,spc<<,v);
update(mid+,r,ll,rr,spc<<|,v);
pushup(spc);
return ;
}
int maxq(int l,int r,int ll,int rr,int spc)
{
if(ll>r||l>rr)
return -0x3f3f3f3f;
if(ll<=l&&r<=rr)
return ter[spc].maxval;
int mid=(l+r)>>;
ppushdown(spc);
return std::max(maxq(l,mid,ll,rr,spc<<),maxq(mid+,r,ll,rr,spc<<|));
}
int query(int l,int r,int pos,int spc)
{
if(l==r)
return ter[spc].maxval;
ppushdown(spc);
int mid=(l+r)>>;
if(pos<=mid)
return query(l,mid,pos,spc<<);
return query(mid+,r,pos,spc<<|);
}
void build(int l,int r,int spc)
{
if(l==r)
{
ter[spc].maxval=p[pos[l]].dp;
return ;
}
int mid=(l+r)>>;
build(l,mid,spc<<);
build(mid+,r,spc<<|);
pushup(spc);
return ;
}
void ade(int f,int t)
{
cnt++;
e[cnt].twd=t;
e[cnt].lst=p[f].hd;
p[f].hd=cnt;
return ;
}
void dfs(int x,int f)
{
p[x].dp=p[f].dp+;
p[x].fa[]=f;
pos[++dfn]=x;
p[x].ind=dfn;
for(int i=;i<=;i++)
p[x].fa[i]=p[p[x].fa[i-]].fa[i-];
for(int i=p[x].hd;i;i=e[i].lst)
{
int to=e[i].twd;
if(to==f)
continue;
tr[to].fa=x;
dfs(to,x);
}
p[x].oud=dfn;
return ;
}
int Lca(int x,int y)
{
if(p[x].dp<p[y].dp)
std::swap(x,y);
for(int i=;i>=;i--)
{
if(p[p[x].fa[i]].dp>=p[y].dp)
x=p[x].fa[i];
}
if(x==y)
return x;
for(int i=;i>=;i--)
{
if(p[x].fa[i]!=p[y].fa[i])
x=p[x].fa[i],y=p[y].fa[i];
}
return p[x].fa[];
}
bool whc(int spc)
{
return tr[tr[spc].fa].rs==spc;
}
void trr(int spc)
{
if(!spc)
return ;
std::swap(lll,rrr);
tr[spc].lzt^=;
return ;
}
void pushdown(int spc)
{
if(tr[spc].lzt)
{
tr[spc].lzt=;
trr(lll);
trr(rrr);
}
return ;
}
void recal(int spc)
{
if(!tr[spc].anc)
recal(tr[spc].fa);
pushdown(spc);
return ;
}
void rotate(int spc)
{
int f=tr[spc].fa;
bool k=whc(spc);
tr[f].ch[k]=tr[spc].ch[!k];
tr[spc].ch[!k]=f;
if(tr[f].anc)
{
tr[f].anc=;
tr[spc].anc=;
}else
tr[tr[f].fa].ch[whc(f)]=spc;
tr[spc].fa=tr[f].fa;
tr[f].fa=spc;
tr[tr[f].ch[k]].fa=f;
return ;
}
void splay(int spc)
{
recal(spc);
while(!tr[spc].anc)
{
int f=tr[spc].fa;
if(tr[f].anc)
{
rotate(spc);
return ;
}
if(whc(spc)^whc(f))
rotate(spc);
else
rotate(f);
rotate(spc);
}
return ;
}
int leftpos(int spc)
{
pushdown(spc);
while(lll)
{
spc=lll;
pushdown(spc);
}
return spc;
}
void access(int spc)
{
int lst=,x;
while(spc)
{
splay(spc);
tr[lst].anc=;
tr[rrr].anc=;
x=leftpos(rrr);
if(x&&!sta)
update(,n,p[x].ind,p[x].oud,,);
x=leftpos(lst);
if(x&&!sta)
update(,n,p[x].ind,p[x].oud,,-);
rrr=lst;
lst=spc;
spc=tr[spc].fa;
}
return ;
}
void Mtr(int spc)
{
access(spc);
splay(spc);
trr(spc);
return ;
}
void split(int x,int y)
{
Mtr(x);
access(y);
splay(y);
return ;
}
void link(int x,int y)
{
split(x,y);
tr[x].fa=y;
return ;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
tr[i].anc=true;
}
for(int i=;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
ade(a,b);
ade(b,a);
}
dfs(,);
build(,n,);
sta=false;
while(m--)
{
int cmd;
scanf("%d",&cmd);
if(cmd==)
{
int x;
scanf("%d",&x);
Mtr();
access(x);
}else if(cmd==)
{
int ans=;
int x,y;
scanf("%d%d",&x,&y);
int z=Lca(x,y);
ans+=query(,n,p[x].ind,);
ans+=query(,n,p[y].ind,);
ans-=query(,n,p[z].ind,)<<;
printf("%d\n",ans);
}else{
int x;
scanf("%d",&x);
printf("%d\n",maxq(,n,p[x].ind,p[x].oud,));
}
}
return ;
}

BZOJ4817: [Sdoi2017]树点涂色(LCT)的更多相关文章

  1. [BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)

    4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 692  Solved: 408[Submit][Status ...

  2. BZOJ4817[Sdoi2017]树点涂色——LCT+线段树

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

  3. 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树

    [BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...

  4. [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)

    4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 629  Solved: 371[Submit][Status ...

  5. [Sdoi2017]树点涂色 [lct 线段树]

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

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

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

  7. 【bzoj4817】树点涂色 LCT+线段树+dfs序

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

  8. BZOJ4817 [Sdoi2017]树点涂色 【LCT + 线段树】

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

  9. 【bzoj4817】[Sdoi2017]树点涂色 LCT+LCA+线段树

    题目描述 给出一棵n个点,以1为根的有根树,每个点初始染有互不相同的颜色.定义一条路径的权值为路径上的颜色种类数.现有m次操作,每次操作为以下三种之一: 1 x: 把点x到根节点的路径上所有的点染上一 ...

随机推荐

  1. poj1014 hdu1059 Dividing 多重背包

    有价值为1~6的宝物各num[i]个,求能否分成价值相等的两部分. #include <iostream> #include <cstring> #include <st ...

  2. Programming Languages - Coursera 整理

    找到并学习这门课的原因: 想要学习 functional programming Week1 Introduction and Course-Wide Information week1 很轻松, 主 ...

  3. BZOJ 2836 树链剖分+线段树

    思路: 链剖+线段树裸题 重链的标号就是DFS序 所以查子树的时候每回就 query(change[x],change[x]+size[x]-1) 就好了 剩下的应该都会吧.. //By Sirius ...

  4. HDU2665 kth number 线段树做法

    题意:求区间第k小 思路: 线段树 每个节点上保存 当前区间已经排序好的序列 (归并一下就好了嘛 复杂度 O(l)的) 这样建树的时空复杂度都是 O(nlogn)的 对于 每次询问 二分一个答案 在树 ...

  5. Gym - 100203G Good elements 水+模拟

    题意:good element的定义是a[i]在1~i-1中任取三个数(可以重复)的和能等于a[i] 思路:vis[x]标记一下任两个数的和,处理a[i]时枚举1~i-1判断vis[a[i] - a[ ...

  6. OpenGL编程逐步深入(四)Shaders

    OpenGl 中的 Shader在一些中文书籍或资料中都被翻译为"着色器", 单从字面意思也看不出Shader到底是什么,Shader实际上就是一段代码,用于完成特定功能的一个模块 ...

  7. 轻量级记事本工具:CintaNotes

    本片文章介绍CintaNotes小工具 功能介绍: 方便.快捷的记录笔记: 快捷地从任何地方等截取内容生成笔记: 高效的记事本内容查询: 轻松的标签管理 支持移动设备和电脑同步(估计要收费) 官网下载 ...

  8. Scrapy 框架介绍

    Scrapy 框架 Scrapy,Python开发的一个快速.高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据.Scrapy用途广泛,可以用于数据挖掘.监测和自动化测试. ...

  9. 关于【搭建LAMP环境时,php测试页面打不开】解决

    关于[搭建LAMP环境时,php测试页面打不开]解决 〇.我的测试页面是: http://172.30.124.10/index.php 用火狐打不开,如下图. 一.httpd已经启动了(system ...

  10. Reuse Is About People and Education, Not Just Architecture

     Reuse Is About People and Education, Not Just Architecture Jeremy Meyer you MigHT AdopT THE AppRoA ...