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到根节点的路径上所有的点染上一 ...
随机推荐
- POJ 3225 Help with Intervals(线段树)
POJ 3225 Help with Intervals 题目链接 集合数字有的为1,没有为0,那么几种操作相应就是置为0或置为1或者翻转,这个随便推推就能够了,然后开闭区间的处理方式就是把区间扩大成 ...
- shu_1171 十->二进制转换(输入输出控制)
cid=1079&pid=19">http://202.121.199.212/JudgeOnline/problem.php?cid=1079&pid=19 分析:主 ...
- 流水线技术原理和Verilog HDL实现
所谓流水线处理,如同生产装配线一样,将操作执行工作量分成若干个时间上均衡的操作段,从流水线的起点连续地输入,流水线的各操作段以重叠方式执行.这使得操作执行速度只与流水线输入的速度有关,而与处理所需的时 ...
- 【Henu ACM Round#16 B】 Bear and Colors
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] O(n^2)枚举每一个区间. 然后维护这个区间里面的"统治数字"是什么. 对于每个区间cnt[统治数字]++; ...
- Starting nagios:This account is currently not available.
解决方式: 又一次安装php 再重新启动apache 再启动nagios 再訪问:http://ip/nagios 我的问题就是 解决的.
- LeetCode 258 Add Digits(数字相加,数字根)
翻译 给定一个非负整型数字,反复相加其全部的数字直到最后的结果仅仅有一位数. 比如: 给定sum = 38,这个过程就像是:3 + 8 = 11.1 + 1 = 2.由于2仅仅有一位数.所以返回它. ...
- Spark 性能相关參数配置具体解释-任务调度篇
作者:刘旭晖 Raymond 转载请注明出处 Email:colorant at 163.com BLOG:http://blog.csdn.net/colorant/ 随着Spark的逐渐成熟完好, ...
- C# 插入排序 冒泡排序 选择排序 高速排序 堆排序 归并排序 基数排序 希尔排序
C# 插入排序 冒泡排序 选择排序 高速排序 堆排序 归并排序 基数排序 希尔排序 以下列出了数据结构与算法的八种基本排序:插入排序 冒泡排序 选择排序 高速排序 堆排序 归并排序 基数排序 希尔排序 ...
- Image-Loader LruMemoryCache
这段时间在研究Universal-Image-Loader 这个图片处理开源框架,这里主要分析一下它的LRU(Least Resently Used,最近最少使用算法)内存缓存的实现. 在UIL它提供 ...
- .net运行项目的几种形式
1.通过配置IIS 2.通过VS运行项目 3.发布到测试服务器 不同于PHP的发布,直接把相关的类文件传入ftp即可. .net的发布是编译好dll文件,将dll文件传入即可. 比如改了某个文件,就把 ...