题目:

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. 初步认识Spring MVC框架

    Spring MVC 框架和Struts2等一样属于MVC框架,用于处理页面和后台的交互,据说它的效率要高于Struts2.下面县先说一下Spring MVC的结构,Spring MVC主要由Disp ...

  2. 【BZOJ3651】网络通信 LCT

    [BZOJ3651]网络通信 Description 有一个由M 条电缆连接的 N 个站点组成的网络.为了防止垄断,由 C 个公司控制所有的电缆,规定任何公司不能控制连接同一个站点的两条以上的电缆(可 ...

  3. openCV图像形态学

    #include <cv.h> #include <highgui.h> #include <stdio.h> //平滑处理 int main() { IplIma ...

  4. springboot工程的结构

    1 springboot的工程结构是什么 就是我们组织springboot工程时遵循的代码的目录结构. 2 spring initializr创建的工程的目录结构 源码目录:src/main/java ...

  5. every row of W is a classifier for one of the classes

    every row of W is a classifier for one of the classes As we saw above, every row of W is a classifie ...

  6. Frobenius Norm

    http://mathworld.wolfram.com/FrobeniusNorm.html

  7. [DBNETLIB][ConnectionOpen(Connect()).]SQL Server 不存在或拒绝访问 数据库错误 解决办法总结

    连接数据库报错:“数据库异常:[DBNETLIB] [ConnectionOpen(Connenct()).] Sqlserver 不存在或拒绝访问” 原因: 1.查看是不是没有在数据库中添加数据库服 ...

  8. 程序运行之ELF文件结构

    ELF目标文件格式的最前部是ELF文件头.包含了整个文件的基本属性.比如ELF文件版本,目标机器型号,程序入口地址等.然后是ELF的各个段,其中ELF文件中与段有关的重要结构就是段表.段表描述了ELF ...

  9. sublime运行Python

    1.首先安装Python 我这里安装的是Python的3.7版本. 这里有两种安装方式 第一种: 默认路径安装,勾选添加到path复选框(这种情况,sublime可以直接运行Python了) 第二种: ...

  10. (转)复习TCP/IP协议与Http协议的区别

    TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据.关于TCP/IP和HTTP协议的关系,网络有一段比较容易理解的介绍:“我们在传输数据时,可以只 ...