[Bzoj4817] [Sdoi2017]树点涂色 (LCT神题)
4817: [Sdoi2017]树点涂色
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 629 Solved: 371
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
Sample Output
题解:
其实这道题考的十分妙啊,对LCT的虚实边性质进行了充分的利用。
当lca和其中一个相同时,我们发现还是减多了,还是得加回来。
一条链的情况自己画图也是同理的。这样对于操作2就用线段树轻松维护了。
操作3????不就是线段树dfs序查询子树吗。
这样我们就神奇的利用了LCT的性质把一道看似树剖的题做成了LCT神题。。
AC代码:
过了样例直接交,一遍交过的酸爽
# include <iostream>
# include <cstdio>
# include <cstring>
using namespace std;
const int N = 2e5 + ;
int st[N],ed[N],fa[N],ch[N][],s[N << ],la[N << ],n,m,head[N],dt;
struct Edge{
int to,nex;
}edge[N << ];
void AddEdge(int u,int v)
{
edge[++dt] = (Edge){v,head[u]};
head[u] = dt;
}
bool isroot(int x){return ch[fa[x]][] != x && ch[fa[x]][] != x;}
void rotate(int x,int d)
{
int pre = fa[x],g = fa[pre],nex = ch[x][d];
ch[pre][d ^ ] = nex;
if(nex)fa[nex] = pre;
fa[x] = g;
if(!isroot(pre))ch[g][ch[g][] == pre] = x;
ch[x][d] = pre;
fa[pre] = x;
}
void splay(int x)
{
int pre,g;
while(!isroot(x))
{
pre = fa[x],g = fa[pre];
if(!isroot(pre) && !((ch[pre][] == x) ^ (ch[g][] == pre)))rotate(pre,ch[pre][] == x);
rotate(x,ch[pre][] == x);
}
}
int find(int x){while(ch[x][])x = ch[x][];return x;}
void push(int x){s[x] = max(s[x << ],s[x << | ]);}
void down(int x)
{
s[x << ] += la[x];s[x << | ] += la[x];
la[x << | ] += la[x];la[x << ] += la[x];
la[x] = ;
}
void updata(int L,int R,int l,int r,int rt,int d)
{
if(L <= l && r <= R){s[rt] += d;la[rt] += d;return;}
down(rt);int mid = l + r >> ;
if(L <= mid)updata(L,R,l,mid,rt << ,d);
if(R > mid)updata(L,R,mid + ,r,rt << | ,d);
push(rt);
}
int Query(int L,int R,int l,int r,int rt)
{
if(L <= l && r <= R)return s[rt];
down(rt);int mid = l + r >> ;
if(L > mid)return Query(L,R,mid + ,r,rt << | );
if(R <= mid)return Query(L,R,l,mid,rt << );
return max(Query(L,R,l,mid,rt << ),Query(L,R,mid + ,r,rt << | ));
}
int ask(int x){return Query(st[x],st[x],,n,);}
void access(int x)
{
int y = ,t;
while(x)
{
splay(x);
if(t = find(ch[x][]))updata(st[t],ed[t],,n,,);
ch[x][] = y;if(t = find(y))updata(st[t],ed[t],,n,,-);
y = x;x = fa[x];
}
}
int hson[N],sz[N],tot,top[N],dep[N],Fa[N],id[N];
void dfs(int u)
{
sz[u] = ;
for(int i = head[u];i;i = edge[i].nex)
{
if(sz[edge[i].to])continue;
Fa[edge[i].to] = u;
dep[edge[i].to] = dep[u] + ;
dfs(edge[i].to);
sz[u] += sz[edge[i].to];
if(sz[hson[u]] < sz[edge[i].to])hson[u] = edge[i].to;
}
}
void dfs(int u,int tp)
{
top[u] = tp;st[u] = ++tot;id[tot] = u;
if(hson[u])dfs(hson[u],tp);
for(int i = head[u];i;i = edge[i].nex)
if(!st[edge[i].to])dfs(edge[i].to,edge[i].to);
ed[u] = tot;
}
int lca(int x,int y)
{
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]])swap(x,y);
x = Fa[top[x]];
}
return dep[x] < dep[y] ? x : y;
}
int Q1(int u,int v){return ask(u) + ask(v) - * ask(lca(u,v)) + ;}
int Q2(int u){return Query(st[u],ed[u],,n,);}
int main()
{
scanf("%d %d",&n,&m);int tp,x,y;
for(int i = ;i < n;i++)
{
scanf("%d %d",&x,&y);
AddEdge(x,y);AddEdge(y,x);
}
dfs();dfs(,);
for(int i = ;i <= n;i++)updata(st[i],ed[i],,n,,),fa[i] = Fa[i];
while(m--)
{
scanf("%d",&tp);
if(tp == )scanf("%d",&x),access(x);
if(tp == )scanf("%d %d",&x,&y),printf("%d\n",Q1(x,y));
if(tp == )scanf("%d",&x),printf("%d\n",Q2(x));
}
}
[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)
Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...
- BZOJ4817[Sdoi2017]树点涂色——LCT+线段树
题目描述 Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色.Bob可能会进 ...
- 【BZOJ4817】[Sdoi2017]树点涂色 LCT+线段树
[BZOJ4817][Sdoi2017]树点涂色 Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路径的权值是:这条路 ...
- [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到根节点的路径上所有的点染上一 ...
随机推荐
- dns2tcp使用教程
在2010年6月的更新(也是迄今为止最新的更新)后,其源代码支持编译为Windows平台的可执行程序.而且此工具使用C语言开发编写,不需要TUN/TAP,所以大大加强了它的可用性. 下载 当前最新的0 ...
- DROP TYPE - 删除一个用户定义数据类型
SYNOPSIS DROP TYPE name [, ...] [ CASCADE | RESTRICT ] DESCRIPTION 描述 DROP TYPE 将从系统表里删除用户定义的类型. 只有类 ...
- Python小记-- 读取当前目录下所有文件名
# -*- coding: utf-8 -*- import os def file_name(file_dir): with open("SelectAllFiles.txt", ...
- Node.js 创建server服务器
var http=require('http'); //引入http模块 var server=http.createServer(function(req,res){ //创建一个server r ...
- LCIS 最长上升公共子序列问题
首先点名一个串叫 L1,另一个叫L2. 明显的是一个DP,那么我们来探讨下如何求得答案. 朴素的算法 首先我们定义状态$dp[ i ][ j ]$表示L1中前i个与L2中前j个的最长公共上升子序列. ...
- 如何用纯 CSS 创作一个冒着热气的咖啡杯
效果预览 在线演示 按下右侧的"点击预览"按钮在当前页面预览,点击链接全屏预览. https://codepen.io/zhang-ou/pen/xjXxoz 可交互视频教程 此视 ...
- Verdi:内存不足
如果进行Verdi compile时,出现memory资源不够用.有可能case中出现了问题(或许发生了死循环,造成内存严重占用),此时尽量瘦身TC_FILE_LIST文件,缩小问题case的范围.
- CentOS 6.5 x64 安装MySql 5.6
1.检测是否已经安装MySQL,输入以下命令 rpm -qa | grep mysql 如果存在,我们输入以下命令来删除 //强力删除 rpm -e --nodeps mysql 2.安装前环境准备 ...
- 【转】错误: ORA-01591: 锁被未决分布式事务处理 7.2.428982 持有--解决方案
SQL 错误: ORA-01591: 锁被未决分布式事务处理 7.2.428982 持有 01591. 00000 - "lock held by in-doubt distributed ...
- vim 系列
http://blog.csdn.net/laogaoav/article/details/17370269 非常不错