BZOJ4817: [Sdoi2017]树点涂色(LCT)
Description
Input
Output
Sample Input
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
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)的更多相关文章
- [BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 692 Solved: 408[Submit][Status ...
- BZOJ4817[Sdoi2017]树点涂色——LCT+线段树
题目描述 Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进 ...
- 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树
[BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...
- [Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 629 Solved: 371[Submit][Status ...
- [Sdoi2017]树点涂色 [lct 线段树]
[Sdoi2017]树点涂色 题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值 考场发现这个信息是可减的,但是没想到lct 特意设计成lct的形式! 如何求颜色数? ...
- BZOJ 4817 [SDOI2017]树点涂色 (LCT+线段树维护dfs序)
题目大意:略 涂色方式明显符合$LCT$里$access$操作的性质,相同颜色的节点在一条深度递增的链上 用$LCT$维护一个树上集合就好 因为它维护了树上集合,所以它别的啥都干不了了 发现树是静态的 ...
- 【bzoj4817】树点涂色 LCT+线段树+dfs序
Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...
- BZOJ4817 [Sdoi2017]树点涂色 【LCT + 线段树】
题目 Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进行这 ...
- 【bzoj4817】[Sdoi2017]树点涂色 LCT+LCA+线段树
题目描述 给出一棵n个点,以1为根的有根树,每个点初始染有互不相同的颜色.定义一条路径的权值为路径上的颜色种类数.现有m次操作,每次操作为以下三种之一: 1 x: 把点x到根节点的路径上所有的点染上一 ...
随机推荐
- poj1014 hdu1059 Dividing 多重背包
有价值为1~6的宝物各num[i]个,求能否分成价值相等的两部分. #include <iostream> #include <cstring> #include <st ...
- Programming Languages - Coursera 整理
找到并学习这门课的原因: 想要学习 functional programming Week1 Introduction and Course-Wide Information week1 很轻松, 主 ...
- BZOJ 2836 树链剖分+线段树
思路: 链剖+线段树裸题 重链的标号就是DFS序 所以查子树的时候每回就 query(change[x],change[x]+size[x]-1) 就好了 剩下的应该都会吧.. //By Sirius ...
- HDU2665 kth number 线段树做法
题意:求区间第k小 思路: 线段树 每个节点上保存 当前区间已经排序好的序列 (归并一下就好了嘛 复杂度 O(l)的) 这样建树的时空复杂度都是 O(nlogn)的 对于 每次询问 二分一个答案 在树 ...
- Gym - 100203G Good elements 水+模拟
题意:good element的定义是a[i]在1~i-1中任取三个数(可以重复)的和能等于a[i] 思路:vis[x]标记一下任两个数的和,处理a[i]时枚举1~i-1判断vis[a[i] - a[ ...
- OpenGL编程逐步深入(四)Shaders
OpenGl 中的 Shader在一些中文书籍或资料中都被翻译为"着色器", 单从字面意思也看不出Shader到底是什么,Shader实际上就是一段代码,用于完成特定功能的一个模块 ...
- 轻量级记事本工具:CintaNotes
本片文章介绍CintaNotes小工具 功能介绍: 方便.快捷的记录笔记: 快捷地从任何地方等截取内容生成笔记: 高效的记事本内容查询: 轻松的标签管理 支持移动设备和电脑同步(估计要收费) 官网下载 ...
- Scrapy 框架介绍
Scrapy 框架 Scrapy,Python开发的一个快速.高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据.Scrapy用途广泛,可以用于数据挖掘.监测和自动化测试. ...
- 关于【搭建LAMP环境时,php测试页面打不开】解决
关于[搭建LAMP环境时,php测试页面打不开]解决 〇.我的测试页面是: http://172.30.124.10/index.php 用火狐打不开,如下图. 一.httpd已经启动了(system ...
- 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 ...