[BZOJ4817]树点涂色
第一个操作比较麻烦,但可以看出它和lct里的access操作差不多,所以可以利用lct的性质巧妙维护操作1
直接用lct维护树中同颜色的链(因为染色操作是从$x$染到根所以同颜色的点一定形成一条链),权值就存$x$到根的路径权值$v_x$
对于操作1,在access每一次切换$x$的实儿子时,把原实儿子在splay中最左的点(也就是在原树中在$x$以下且同一条链上深度最浅的点)的子树权值$+1$,把新实儿子在splay中最左的点的子树权值$-1$(每一次切换,原实儿子的子树到根的路径上多了一种颜色,新实儿子的子树到根的路径上少了一种颜色)

对于操作2,容易看出答案是$v_x+v_y-2v_{lca_{x,y}}+1$
对于操作3,直接用线段树维护dfs序,就是查询区间最大值
这个lct的性质用得好哇
#include<stdio.h>
void swap(int&a,int&b){a^=b^=a^=b;}
int max(int a,int b){return a>b?a:b;}
int n,a[100010];
struct seg{
int mx[400010],d[400010];
void pushup(int x){mx[x]=max(mx[x<<1],mx[x<<1|1]);}
void build(int l,int r,int x){
if(l==r){
mx[x]=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
pushup(x);
}
void add(int x,int v){
d[x]+=v;
mx[x]+=v;
}
void pushdown(int x){
if(d[x]){
add(x<<1,d[x]);
add(x<<1|1,d[x]);
d[x]=0;
}
}
void modify(int L,int R,int v,int l,int r,int x){
if(L<=l&&r<=R)return add(x,v);
pushdown(x);
int mid=(l+r)>>1;
if(L<=mid)modify(L,R,v,l,mid,x<<1);
if(mid<R)modify(L,R,v,mid+1,r,x<<1|1);
pushup(x);
}
int query(int L,int R,int l,int r,int x){
if(L<=l&&r<=R)return mx[x];
pushdown(x);
int mid=(l+r)>>1,ans=-1;
if(L<=mid)ans=max(ans,query(L,R,l,mid,x<<1));
if(mid<R)ans=max(ans,query(L,R,mid+1,r,x<<1|1));
return ans;
}
}s;
struct tree{
int h[100010],nex[200010],to[200010],in[100010],ou[100010],fa[100010][17],dep[100010],M;
void add(int a,int b){
M++;
to[M]=b;
nex[M]=h[a];
h[a]=M;
}
void dfs(int x){
in[x]=++M;
for(int i=h[x];i;i=nex[i]){
if(to[i]!=fa[x][0]){
fa[to[i]][0]=x;
dep[to[i]]=dep[x]+1;
dfs(to[i]);
}
}
ou[x]=M;
}
void pre(){
int i,j,x,y;
for(i=1;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dep[1]=1;
M=0;
dfs(1);
for(j=1;j<17;j++){
for(i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];
}
for(i=1;i<=n;i++)a[in[i]]=dep[i];
s.build(1,n,1);
}
void modify(int x,int v){
s.modify(in[x],ou[x],v,1,n,1);
}
int get(int x){
return s.query(in[x],in[x],1,n,1);
}
int sub(int x){
return s.query(in[x],ou[x],1,n,1);
}
int lca(int x,int y){
int i;
if(dep[x]<dep[y])swap(x,y);
for(i=16;i>=0;i--){
if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
}
if(x==y)return x;
for(i=16;i>=0;i--){
if(fa[x][i]!=fa[y][i]){
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
}t;
struct lct{
int fa[100010],ch[100010][2],l[100010];
void pre(){
int i;
for(i=2;i<=n;i++)fa[i]=t.fa[i][0];
for(i=1;i<=n;i++)l[i]=i;
}
#define ls ch[x][0]
#define rs ch[x][1]
void pushup(int x){
if(ls)
l[x]=l[ls];
else
l[x]=x;
}
void rot(int x){
int y,z,f,b;
y=fa[x];
z=fa[y];
f=ch[y][0]==x;
b=ch[x][f];
fa[x]=z;
fa[y]=x;
if(b)fa[b]=y;
ch[x][f]=y;
ch[y][f^1]=b;
if(ch[z][0]==y)ch[z][0]=x;
if(ch[z][1]==y)ch[z][1]=x;
pushup(y);
pushup(x);
}
bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
void splay(int x){
int y,z;
while(!isrt(x)){
y=fa[x];
z=fa[y];
if(!isrt(y))rot((ch[z][0]==y&&ch[y][0]==x)||(ch[z][1]==y&&ch[y][1]==x)?y:x);
rot(x);
}
}
void access(int x){
int y=0;
while(x){
splay(x);
if(rs)t.modify(l[rs],1);
rs=y;
if(y)t.modify(l[y],-1);
pushup(x);
y=x;
x=fa[x];
}
}
}l;
int main(){
int m,i,x,y;
scanf("%d%d",&n,&m);
t.pre();
l.pre();
while(m--){
scanf("%d%d",&i,&x);
if(i==1)l.access(x);
if(i==2){
scanf("%d",&y);
printf("%d\n",t.get(x)+t.get(y)-(t.get(t.lca(x,y))<<1)+1);
}
if(i==3)printf("%d\n",t.sub(x));
}
}
[BZOJ4817]树点涂色的更多相关文章
- [SDOI2017][bzoj4817] 树点涂色 [LCT+线段树]
题面 传送门 思路 $LCT$ 我们发现,这个1操作,好像非常像$LCT$里面的$Access$啊~ 那么我们尝试把$Access$操作魔改成本题中的涂色 我们令$LCT$中的每一个$splay$链代 ...
- 【BZOJ4817】树点涂色(LCT,线段树,树链剖分)
[BZOJ4817]树点涂色(LCT,线段树,树链剖分) 题面 BZOJ Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义 ...
- 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树
[BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...
- [BZOJ4817][SDOI2017]树点涂色(LCT+DFS序线段树)
4817: [Sdoi2017]树点涂色 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 692 Solved: 408[Submit][Status ...
- 【BZOJ4817】【SDOI2017】树点涂色 [LCT][线段树]
树点涂色 Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description Bob有一棵n个点的有根树,其中1 ...
- [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的形式! 如何求颜色数? ...
- 「SDOI2017」树点涂色 解题报告
「SDOI2017」树点涂色 我sb的不行了 其实一开始有一个类似动态dp的想法 每个点维护到lct树上到最浅点的颜色段数,然后维护一个\(mx_{0,1}\)也就是是否用虚儿子的最大颜色 用个set ...
- P3703 [SDOI2017]树点涂色
P3703 [SDOI2017]树点涂色 链接 分析: 首先对于询问,感觉是线段树维护dfs序,每个点记录到根的颜色个数.第二问差分,第三问区间取max. 那么考虑修改,每次将一个点的颜色变成和父节点 ...
随机推荐
- SCOI2005 互不侵犯 [状压dp]
题目传送门 题目大意:有n*n个格子,你需要放置k个国王使得它们无法互相攻击,每个国王的攻击范围为上下左走,左上右上左下右下,共8个格子,求最多的方法数 看到题目,是不是一下子就想到了玉米田那道题,如 ...
- Educational Codeforces Round 55 (Rated for Div. 2):E. Increasing Frequency
E. Increasing Frequency 题目链接:https://codeforces.com/contest/1082/problem/E 题意: 给出n个数以及一个c,现在可以对一个区间上 ...
- jquery、zepto冲突
<script type="text/javascript" src="js/jquery.min.js"></script> < ...
- nodejs与sqlite
//打开数据库var db = new sqlite3.Database('xx.db'); // 关闭数据库db.close(); db.run('xx'); // 数据库对象的run函数可以执行 ...
- c语言几个字符串处理函数的简单实现
直接贴代码: char* strcpy(char *a,char*b){//把字符串b全部拷贝到a中 assert(a != nullptr&&b != nullptr); char ...
- bzoj 1951 lucas crt 费马小定理
首先假设输入的是n,m 我们就是要求m^(Σ(c(n,i) i|n)) mod p 那么根据费马小定理,上式等于 m^(Σ(c(n,i) i|n) mod (p-1)) mod p 那么问题的关键就 ...
- 160多条Windows 7 “运行”命令
160多条Windows 7 “运行”命令: 删除或更改应用程序 = control appwiz.cpl 添加设备 = devicepairingwizard 蓝牙文件传输 = fsquirt ...
- AtCoder Regular Contest 092 C D E F
C - 2D Plane 2N Points 题意 二维平面上有\(N\)个红点,\(N\)个蓝点,一个红点和一个蓝点能配成一对当且仅当\(x_r<x_b\)且\(y_r<y_b\). 问 ...
- SEH
@author: dlive SEH是Windows的异常处理机制,在程序源代码中使用__try,__catch,__finally关键字来具体实现. 但SEH与C++的try, catch异常处理不 ...
- centOS 7 部署samba
部署samba **每个用户有自己的目录,可以浏览内容,也可以删除** 清空防火墙规则 [root@bogon ~]# iptables -F 安装samba [root@bogon ~]# yum ...