题目:

Bob有一棵n个点的有根树,其中1号点是根节点。Bob在每个点上涂了颜色,并且每个点上的颜色不同.

定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色。

Bob可能会进行这几种操作:

1 x: 把点x到根节点的路径上所有的点染上一种没有用过的新颜色。

2 x y: 求x到y的路径的权值。

3 x y: 在以x为根的子树中选择一个点,使得这个点到根节点的路径权值最大,求最大权值。

1<=n,m<=100000

题解:

这道题就是重组病毒的弱化版.

要是HE省选也考这种我会的题目超级弱化版就好了

跟重组病毒一样,我们发现第一个操作其实就是把一条链到根的颜色变得相同了.

如果我们用一条连向fa的虚边表示这个点的颜色和父亲的节点的颜色不同

反之,实边表示相同.那么如果求两点路径权值就是求路径上虚边的个数+1(因lca未被统计)

然后我们发现第一个操作其实就是Access.

然后外部进行树链剖分,在LCT Access的切断和连接实边的时候更新外部数据结构即可.

2,3两个操作都可以分别维护.

对于操作2 : 若某点连向fa为虚边对单点赋值为1,否则为0.然后直接跳top统计即可.

对于操作3 : 对每个点维护一个这个点到根的路径权,每次若连向fa的边改变,做区间修改即可,查询即区间最值.

代码比重组病毒好写多了

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;static char ch;static bool flag;flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=(x<<1)+(x<<3)+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
const int maxn = 100010;
struct Edge{
int to,next;
}G[maxn<<1];
int head[maxn],cnt;
void add(int u,int v){
G[++cnt].to = v;
G[cnt].next = head[u];
head[u] = cnt;
}
int n,m;
namespace seg{
#define v G[i].to
int top[maxn],son[maxn],siz[maxn];
int dep[maxn],ind[maxn],oud[maxn];
int dfs_clock,fa[maxn];
void dfs(int u){
siz[u] = 1;
for(int i = head[u];i;i=G[i].next){
if(v == fa[u]) continue;
fa[v] = u;
dep[v] = dep[u] + 1;
dfs(v);
siz[u] += siz[v];
if(siz[son[u]] < siz[v]) son[u] = v;
}
}
void dfs(int u,int tp){
top[u] = tp;
ind[u] = ++ dfs_clock;
if(son[u]) dfs(son[u],tp);
for(int i = head[u];i;i=G[i].next){
if(v == fa[u] || v == son[u]) continue;
dfs(v,v);
}
oud[u] = dfs_clock;
}
#undef v
struct segTree{
int sum[maxn<<2],tag[maxn<<2],mx[maxn<<2];
inline void pushdown(int rt,int l,int r){
if(rt == 0 || tag[rt] == 0) return ;
int mid = l+r >> 1;
sum[rt<<1] += tag[rt]*(mid - l + 1);
sum[rt<<1|1] += tag[rt]*(r - mid);
mx[rt<<1] += tag[rt];
mx[rt<<1|1] += tag[rt];
tag[rt<<1] += tag[rt];
tag[rt<<1|1] += tag[rt];
tag[rt] = 0;
}
void modify(int rt,int l,int r,int L,int R,int d){
if(L <= l && r <= R){
tag[rt] += d;
sum[rt] += d*(r - l + 1);
mx[rt] += d;
return ;
}
int mid = l+r >> 1;pushdown(rt,l,r);
if(L <= mid) modify(rt<<1,l,mid,L,R,d);
if(R > mid) modify(rt<<1|1,mid+1,r,L,R,d);
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
mx[rt] = max(mx[rt<<1],mx[rt<<1|1]);
}
int query_max(int rt,int l,int r,int L,int R){
if(L <= l && r <= R) return mx[rt];
int mid = l+r >> 1;pushdown(rt,l,r);
if(R <= mid) return query_max(rt<<1,l,mid,L,R);
if(L > mid) return query_max(rt<<1|1,mid+1,r,L,R);
return max(query_max(rt<<1,l,mid,L,R),query_max(rt<<1|1,mid+1,r,L,R));
}
int query_sum(int rt,int l,int r,int L,int R){
if(L <= l && r <= R) return sum[rt];
int mid = l+r >> 1;pushdown(rt,l,r);
if(R <= mid) return query_sum(rt<<1,l,mid,L,R);
if(L > mid) return query_sum(rt<<1|1,mid+1,r,L,R);
return query_sum(rt<<1,l,mid,L,R) + query_sum(rt<<1|1,mid+1,r,L,R);
}
}T1,T2;
}
namespace lct{
using namespace seg;
struct Node{
Node *ch[2],*fa;
int id;
}mem[maxn],*it,*null;
inline void init(){
it = mem;null = it++;
null->ch[0] = null->ch[1] = null->fa = null;
null->id = -1;
}
inline Node* newNode(){
Node *p = it++;
p->ch[0] = p->ch[1] = p->fa = null;
return p;
}
inline void rotate(Node *p,Node *x){
int k = p == x->ch[1];
Node *y = p->ch[k^1],*z = x->fa;
if(z->ch[0] == x) z->ch[0] = p;
if(z->ch[1] == x) z->ch[1] = p;
if(y != null) y->fa = x;
p->ch[k^1] = x;p->fa = z;
x->ch[k] = y;x->fa = p;
}
inline bool isroot(Node *p){
return (p == null) || (p->fa->ch[0] != p && p->fa->ch[1] != p);
}
inline void Splay(Node *p){
while(!isroot(p)){
Node *x = p->fa,*y = x->fa;
if(isroot(x)) rotate(p,x);
else if((p == x->ch[0])^(x == y->ch[0])) rotate(p,x),rotate(p,y);
else rotate(x,y),rotate(p,x);
}
}
inline void Access(Node *x){
for(Node *y = null;x != null;y = x,x = x->fa){
Splay(x);
Node *p = x->ch[1];
while(p->ch[0] != null) p = p->ch[0];
if(p != null){
T1.modify(1,1,n,ind[p->id],ind[p->id],1);
T2.modify(1,1,n,ind[p->id],oud[p->id],1);
}
p = y;
while(p->ch[0] != null) p = p->ch[0];
if(p != null){
T1.modify(1,1,n,ind[p->id],ind[p->id],-1);
T2.modify(1,1,n,ind[p->id],oud[p->id],-1);
}
x->ch[1] = y;
}
}
}
inline int query(int u,int v){
using namespace seg;
int ret = 0;
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]]) swap(u,v);
ret += T1.query_sum(1,1,n,ind[top[u]],ind[u]);
u = fa[top[u]];
}if(dep[u] > dep[v]) swap(u,v);
if(ind[u] + 1 <= ind[v]) ret += T1.query_sum(1,1,n,ind[u]+1,ind[v]);
return ret;
}
int main(){
using namespace lct;
using namespace seg;
read(n);read(m);
init();
rep(i,1,n) newNode()->id = i;
rg u,v;
rep(i,1,n-1){
read(u);read(v);
add(u,v);add(v,u);
}
dfs(1);dfs(1,1);
rep(i,2,n){
T1.modify(1,1,n,ind[i],ind[i],1);
T2.modify(1,1,n,ind[i],oud[i],1);
(mem+i)->fa = (mem+fa[i]);
}
rg op;
while(m--){
read(op);
if(op == 1){
read(u);
Access(mem+u);
}else if(op == 2){
read(u);read(v);
printf("%d\n",query(u,v)+1);
}else if(op == 3){
read(u);
printf("%d\n",T2.query_max(1,1,n,ind[u],oud[u])+1);
}
}
return 0;
}

bzoj 4817: [Sdoi2017]树点涂色 LCT+树链剖分+线段树的更多相关文章

  1. BZOJ.1758.[WC2010]重建计划(分数规划 点分治 单调队列/长链剖分 线段树)

    题目链接 BZOJ 洛谷 点分治 单调队列: 二分答案,然后判断是否存在一条长度在\([L,R]\)的路径满足权值和非负.可以点分治. 对于(距当前根节点)深度为\(d\)的一条路径,可以用其它子树深 ...

  2. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  3. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  4. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  5. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  6. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

  7. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

  8. [luogu3676] 小清新数据结构题 [树链剖分+线段树]

    题面 传送门 思路 本来以为这道题可以LCT维护子树信息直接做的,后来发现这样会因为splay形态改变影响子树权值平方和,是splay本身的局限性导致的 所以只能另辟蹊径 首先,我们考虑询问点都在1的 ...

  9. 【bzoj3083】遥远的国度 树链剖分+线段树

    题目描述 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn ...

  10. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

随机推荐

  1. 【BZOJ3672】[Noi2014]购票 树分治+斜率优化

    [BZOJ3672][Noi2014]购票 Description  今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会.       ...

  2. 爬虫入门【1】urllib.request库用法简介

    urlopen方法 打开指定的URL urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, ca ...

  3. vue-cli (vue脚手架)

    vue-cli(脚手架):它可以自动生成目录 1.在网速不佳的情况下可以安装cnpm(淘宝镜像)如果网速快可以不用安装cnpm直接进行下一步操作 第一步:在命令行执行(全局安装cnpm) npm in ...

  4. Office Web Apps Server 2013与PDF(二)

    在上一篇文章(Office Web Apps Server 2013与PDF(一))中,曾经介绍了Office Web Apps Server 2013在更新后,可以直接对PDF文档进行在线的查看.不 ...

  5. Modeling of Indoor Positioning Systems Based on Location Fingerprinting

    Kamol Kaemarungsi and Prashant Krishnamurthy Telecommunications Program School of Information Scienc ...

  6. 我的Android进阶之旅------>解决 Error: ShouldNotReachHere() 问题

    在Android项目中创建一个包含main()方法的类,直接右键运行该类时会报如下错误: # # An unexpected error has been detected by Java Runti ...

  7. Linux c编程:同步属性

    就像线程具有属性一样,线程的同步对象(如互斥量.读写锁.条件变量.自旋锁和屏障)也有属性 1.互斥量属性 用pthread_mutexattr_init初始化pthread_mutexattr_t结构 ...

  8. [原创] hadoop学习笔记:wordcout程序实践

    看了官网上的示例:但是给的不是很清楚,这里依托官网给出的示例,加上自己的实践,解析worcount程序的操作 1.首先你的确定你的集群正确安装,并且启动你的集群,应为这个是hadoop2.6.0,所以 ...

  9. [原创] Windows下Eclipse连接hadoop

    1 下载hadoop-eclipse-plugin :我用的是hadoop-eclipse-plugin1.2.1 ,百度自行下载 2 配置插件:将下载的插件解压,把插件放到..\eclipse\pl ...

  10. 【leetcode刷题笔记】Maximal Rectangle

    Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and ...