【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]
树点涂色
Time Limit: 10 Sec Memory Limit: 128 MB
[Submit][Status][Discuss]
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
HINT
Solution
我们将边两端的点颜色相同的边设为实边,不同的设为虚边。那么一次新增颜色的操作显然就是LCT的access操作!access的时候恰是虚边和实边的转换。
那么我们只要用线段树维护每个点到根的贡献,结合dfs序来实现子树加,每次在LCT进行access的时候进行+-1修改,然后询问的时候用区间求和,区间最值求得答案即可。
Code
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long s64; const int ONE = 2e5+; int n,m;
int x,y,P;
int POS[ONE],POSCNT;
int pos[ONE],dfn_cnt,size[ONE],dfn[ONE];
int Dep[ONE],son[ONE],Top[ONE];
int lc[ONE],rc[ONE],fa[ONE],fat[ONE];
int res_max,res_value; inline int get()
{
int res=,Q=; char c;
while( (c=getchar())< || c>)
if(c=='-')Q=-;
if(Q) res=c-;
while((c=getchar())>= && c<=)
res=res*+c-;
return res*Q;
} namespace tree
{
int next[ONE],first[ONE],go[ONE],tot=; void Add(int u,int v)
{
next[++tot]=first[u]; first[u]=tot; go[tot]=v;
next[++tot]=first[v]; first[v]=tot; go[tot]=u;
} void Dfs(int u,int father)
{
pos[u] = ++dfn_cnt; dfn[dfn_cnt] = u;
size[u] = ;
Dep[u] = Dep[father] + ;
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father) continue;
fa[v] = u; fat[v] = u;
Dfs(v,u);
size[u] += size[v];
if(size[v] > size[son[u]]) son[u] = v;
}
} void Dfs_twice(int u,int father)
{
POS[u] = ++POSCNT;
if(son[u])
{
int v=son[u];
Top[v] = Top[u];
Dfs_twice(v,u);
} for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father || v==son[u]) continue;
Top[v] = v;
Dfs_twice(v,u);
}
} int LCA(int x,int y)
{
while(Top[x]!=Top[y])
{
if( Dep[Top[x]] < Dep[Top[y]] ) swap(x,y);
x = fat[Top[x]];
}
if(POS[x] > POS[y]) swap(x,y);
return x;
}
} namespace Seg
{
struct power
{
int add,value;
int maxx;
}Node[ONE*]; void pushdown(int i,int Q)
{
if(Node[i].add)
{
Node[i<<].add += Node[i].add;
Node[i<<|].add += Node[i].add;
Node[i<<].maxx += Node[i].add;
Node[i<<|].maxx += Node[i].add;
Node[i<<].value += Node[i].add * (Q-Q/);
Node[i<<|].value += Node[i].add * (Q/);
Node[i].add = ;
}
} void Build(int i,int l,int r)
{
if(l==r)
{
Node[i].value = Dep[dfn[l]];
Node[i].maxx = Dep[dfn[l]];
return ;
}
int mid = l+r>>;
Build(i<<,l,mid); Build(i<<|,mid+,r);
Node[i].value = Node[i<<].value + Node[i<<|].value;
Node[i].maxx = max(Node[i<<].maxx, Node[i<<|].maxx);
} void Update(int i,int l,int r,int L,int R,int x)
{
if(L<=l && r<=R)
{
Node[i].add += x;
Node[i].value += (r-l+)*x;
Node[i].maxx += x;
return;
}
pushdown(i,r-l+);
int mid = l+r>>;
if(L<=mid) Update(i<<,l,mid,L,R,x);
if(mid+<=R) Update(i<<|,mid+,r,L,R,x); Node[i].value = Node[i<<].value + Node[i<<|].value;
Node[i].maxx = max(Node[i<<].maxx , Node[i<<|].maxx);
} void Query(int i,int l,int r,int L,int R)
{
if(L<=l && r<=R)
{
res_max = max(res_max,Node[i].maxx);
res_value += Node[i].value;
return;
}
pushdown(i,r-l+);
int mid = l+r>>;
if(L<=mid) Query(i<<,l,mid,L,R);
if(mid+<=R) Query(i<<|,mid+,r,L,R);
}
} namespace LCT
{
int is_real(int x)
{
return (lc[fa[x]]==x || rc[fa[x]]==x);
} void Turn(int x)
{
int y = fa[x], z = fa[y];
int b = x==lc[y] ? rc[x]:lc[x]; fa[x] = z; fa[y] = x;
if(b) fa[b] = y; if(z)
{
if(y == lc[z]) lc[z] = x;
else
if(y == rc[z]) rc[z] = x;
} if(x==lc[y]) rc[x]=y,lc[y]=b;
else lc[x]=y,rc[y]=b;
} void Splay(int x)
{
while(is_real(x))
{
if(is_real(fa[x]))
{
if( (lc[fa[x]]==x) == (lc[fa[fa[x]]]==fa[x])) Turn(fa[x]);
else Turn(x);
}
Turn(x);
}
} int find_root(int x)
{
while(lc[x]) x=lc[x];
return x;
} void access(int x)
{
for(int p=x,q=; p; q=p,p=fa[p])
{
Splay(p);
if(rc[p])
{
int N = find_root(rc[p]);
Seg::Update(,,n,pos[N],pos[N]+size[N]-,);
} rc[p] = q;
if(rc[p])
{
int N = find_root(rc[p]);
Seg::Update(,,n,pos[N],pos[N]+size[N]-,-);
}
}
}
} int Getsum(int x,int y)
{
int Ans, Sx, Sy, SLCA, LCA;
LCA = tree::LCA(x,y);
x=pos[x], y=pos[y], LCA=pos[LCA];
res_value = ; Seg::Query(,,n,x,x); Sx = res_value;
res_value = ; Seg::Query(,,n,y,y); Sy = res_value;
res_value = ; Seg::Query(,,n,LCA,LCA); SLCA = res_value;
return Sx+Sy-*SLCA+;
} int Getmax(int x)
{
res_max = ;
Seg::Query(,,n,pos[x],pos[x]+size[x]-);
return res_max;
} int main()
{
n=get(); m=get();
for(int i=;i<=n-;i++)
{
x=get(); y=get();
tree::Add(x,y);
} tree::Dfs(,);
Top[] = , tree::Dfs_twice(,);
Seg::Build(,,n); while(m--)
{
P = get(); x=get();
if(P==)
LCT::access(x);
if(P==)
y=get(), printf("%d\n",Getsum(x,y));
if(P==)
printf("%d\n",Getmax(x));
}
}
【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]的更多相关文章
- 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树
[BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...
- [Sdoi2017]树点涂色 [lct 线段树]
[Sdoi2017]树点涂色 题意:一棵有根树,支持x到根染成新颜色,求x到y颜色数,求x子树里点到根颜色数最大值 考场发现这个信息是可减的,但是没想到lct 特意设计成lct的形式! 如何求颜色数? ...
- [SDOI2017][bzoj4817] 树点涂色 [LCT+线段树]
题面 传送门 思路 $LCT$ 我们发现,这个1操作,好像非常像$LCT$里面的$Access$啊~ 那么我们尝试把$Access$操作魔改成本题中的涂色 我们令$LCT$中的每一个$splay$链代 ...
- BZOJ4817[Sdoi2017]树点涂色——LCT+线段树
题目描述 Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进 ...
- bzoj4817 & loj2001 [Sdoi2017]树点涂色 LCT + 线段树
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4817 https://loj.ac/problem/2001 题解 可以发现这个题就是 bzo ...
- BZOJ 4817 [SDOI2017]树点涂色 (LCT+线段树维护dfs序)
题目大意:略 涂色方式明显符合$LCT$里$access$操作的性质,相同颜色的节点在一条深度递增的链上 用$LCT$维护一个树上集合就好 因为它维护了树上集合,所以它别的啥都干不了了 发现树是静态的 ...
- 【bzoj4817】树点涂色 LCT+线段树+dfs序
Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...
- BZOJ 4817 [Sdoi2017]树点涂色 ——LCT 线段树
同BZOJ3779. SDOI出原题,还是弱化版的. 吃枣药丸 #include <map> #include <cmath> #include <queue> # ...
- BZOJ 4817: [Sdoi2017]树点涂色(lct+线段树)
传送门 解题思路 跟重组病毒这道题很像.只是有了一个询问\(2\)的操作,然后询问\(2\)的答案其实就是\(val[x]+val[y]-2*val[lca(x,y)]+1\)(画图理解).剩下的操作 ...
随机推荐
- 【Android 应用开发】Ubuntu 下 Android Studio 开发工具使用详解
. 基本上可以导入项目开始使用了 ... . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21035637 ...
- 福大软工1816:Alpha(7/10)
Alpha 冲刺 (7/10) 队名:Jarvis For Chat 组长博客链接 本次作业链接 团队部分 团队燃尽图 工作情况汇报 张扬(组长) 过去两天完成了哪些任务: 文字/口头描述: 1.完成 ...
- Spring学习(二)—— java的动态代理机制
在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...
- (三)java字符串
不可变字符串 Java没有字符串类型,而是提供了一个预定义类String. java中的字符串是不可变字符串,因此无法更改某一个字符串变量的内容. 优点:编译器可以让字符串共享.当复制一个字符串时,原 ...
- Directory类的使用、Alt+Shift+F10可以查看其命名空间
对于一个对象,按下Alt+Shift+F10可以查看其命名空间. Directory类的使用 using System; using System.Collections.Generic; using ...
- 图像检测算法Halcon 10的使用
安装完成HALCON之后,在VS项目中添加动态链接库配置项目,并修改此项目属性的包含目录.库目录和链接器.
- React & `event.persist()`
React & event.persist() event.persist() https://reactjs.org/docs/events.html#event-pooling Tabs ...
- Access Denied for user root @localhost 解决方案
问题描述: C:\Users\bo.wang> mysql -u root -p Enter password: ERROR 1045 (28000): Access denied for us ...
- init只创建一次 只有父类的init创建servletContext的对象
init只创建一次 只有父类的init创建servletContext的对象 如果重写父类的方法 但不显示调用父类的init 是不会创建servletContext对象的
- HUAS 1483 mex(莫队算法)
考虑莫队算法,对于区间减小的情况,可以O(1)解决.对于区间增加的情况,可能需要O(n)解决.好在数据不卡莫队. 1200ms过了. 离线+线段树 760ms过了. # include <cst ...