树链剖分——线段树区间合并bzoj染色
线段树区间合并就挺麻烦了,再套个树链就更加鬼畜,不过除了代码量大就没什么其他的了。。
一些细节:线段树每个结点用结构体保存,pushup等合并函数改成返回一个结构体,这样好写一些
struct Seg{
int lc,rc,tot;
Seg(){lc=rc=-;tot=;}
};
Seg seg[maxn<<];int lazy[maxn<<];
Seg pushup(Seg a,Seg b){
if(!a.tot)return b;
if(!b.tot)return a;
Seg res;
res.lc=a.lc,res.rc=b.rc;
res.tot=a.tot+b.tot;
if(a.rc==b.lc)res.tot--;
return res;
}
向上爬时更新操作不用变,但是询问操作需要改变
同样有一些值得注意的地方:向上爬的两条链是有顺序的,合并时顺序不能搞反,也不能像普通树链剖分那样直接swap
int Query(int x,int y){
Seg A,B;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]){
B=pushup(query(id[top[y]],id[y],,n,),B);
y=f[top[y]];
}
else {
A=pushup(query(id[top[x]],id[x],,n,),A);
x=f[top[x]];
}
}
if(id[x]>id[y])
A=pushup(query(id[y],id[x],,n,),A);
else
B=pushup(query(id[x],id[y],,n,),B);
if(A.lc==B.lc)return A.tot+B.tot-;
else return A.tot+B.tot;
}
最后是完整代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
struct Edge{int to,nxt;}edge[maxn<<];
int c[maxn],head[maxn],tot,n; int f[maxn],son[maxn],d[maxn],size[maxn];
int cnt,id[maxn],rk[maxn],top[maxn];
void dfs1(int x,int pre,int deep){
size[x]=,d[x]=deep;
for(int i=head[x];i!=-;i=edge[i].nxt){
int y=edge[i].to;
if(y==pre)continue;
f[y]=x;dfs1(y,x,deep+);size[x]+=size[y];
if(size[son[x]]<size[y])son[x]=y;
}
}
void dfs2(int x,int tp){
top[x]=tp;id[x]=++cnt;rk[cnt]=x;
if(son[x])dfs2(son[x],tp);
for(int i=head[x];i!=-;i=edge[i].nxt){
int y=edge[i].to;
if(y!=son[x] && y!=f[x])dfs2(y,y);
}
} #define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
struct Seg{
int lc,rc,tot;
Seg(){lc=rc=-;tot=;}
};
Seg seg[maxn<<];int lazy[maxn<<];
Seg pushup(Seg a,Seg b){
if(!a.tot)return b;
if(!b.tot)return a;
Seg res;
res.lc=a.lc,res.rc=b.rc;
res.tot=a.tot+b.tot;
if(a.rc==b.lc)res.tot--;
return res;
}
void pushdown(int rt){
if(lazy[rt]<)return;
lazy[rt<<]=lazy[rt<<|]=lazy[rt];
seg[rt<<].lc=seg[rt<<].rc=lazy[rt];
seg[rt<<].tot=;
seg[rt<<|].lc=seg[rt<<|].rc=lazy[rt];
seg[rt<<|].tot=;
lazy[rt]=-;
}
void build(int l,int r,int rt){
if(l==r){
seg[rt].lc=seg[rt].rc=c[rk[l]];
seg[rt].tot=;return;
}
int m=l+r>>;
build(lson);build(rson);
seg[rt]=pushup(seg[rt<<],seg[rt<<|]);
}
void update(int L,int R,int c,int l,int r,int rt){
if(L<=l && R>=r){
lazy[rt]=c;seg[rt].lc=seg[rt].rc=c;
seg[rt].tot=;return;
}
pushdown(rt);
int m=l+r>>;
if(L<=m)update(L,R,c,lson);
if(R>m)update(L,R,c,rson);
seg[rt]=pushup(seg[rt<<],seg[rt<<|]);
}
Seg query(int L,int R,int l,int r,int rt){
if(L<=l && R>=r)return seg[rt];
pushdown(rt);
int m=l+r>>;
Seg res;
if(L<=m)res=pushup(res,query(L,R,lson));
if(R>m)res=pushup(res,query(L,R,rson));
return res;
} void Update(int x,int y,int c){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]])swap(x,y);
update(id[top[x]],id[x],c,,n,);
x=f[top[x]];
}
if(id[x]>id[y])swap(x,y);
update(id[x],id[y],c,,n,);
}
int Query(int x,int y){
Seg A,B;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]){
B=pushup(query(id[top[y]],id[y],,n,),B);
y=f[top[y]];
}
else {
A=pushup(query(id[top[x]],id[x],,n,),A);
x=f[top[x]];
}
}
if(id[x]>id[y])
A=pushup(query(id[y],id[x],,n,),A);
else
B=pushup(query(id[x],id[y],,n,),B);
if(A.lc==B.lc)return A.tot+B.tot-;
else return A.tot+B.tot;
} void init(){
memset(head,-,sizeof head);
memset(lazy,-,sizeof lazy);
tot=;
}
void addedge(int u,int v){
edge[tot].to=v;edge[tot].nxt=head[u];head[u]=tot++;
}
int main(){
init();int q;
cin>>n>>q;
for(int i=;i<=n;i++)cin>>c[i];
for(int i=;i<n;i++){
int x,y;cin>>x>>y;
addedge(x,y);addedge(y,x);
}
cnt=;dfs1(,,),dfs2(,);
build(,n,);
char op[];int x,y,z;
while(q--){
scanf("%s",op);
if(op[]=='Q'){scanf("%d%d",&x,&y);
cout<<Query(x,y)<<'\n';}
if(op[]=='C'){scanf("%d%d%d",&x,&y,&z);Update(x,y,z);}
}
}
树链剖分——线段树区间合并bzoj染色的更多相关文章
- 【bzoj2325】[ZJOI2011]道馆之战 树链剖分+线段树区间合并
题目描述 给定一棵树,每个节点有上下两个格子,每个格子的状态为能走或不能走.m次操作,每次修改一个节点的状态,或询问:把一条路径上的所有格子拼起来形成一个宽度为2的长方形,从起点端两个格子的任意一个开 ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2852 Solved: 1668[Submit][Sta ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...
- BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)
题目链接 BZOJ2243 树链剖分 $+$ 线段树 线段树每个节点维护$lc$, $rc$, $s$ $lc$代表该区间的最左端的颜色,$rc$代表该区间的最右端的颜色 $s$代表该区间的所有连续颜 ...
- BZOJ 3589 动态树 (树链剖分+线段树)
前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...
- bzoj 2157: 旅游【树链剖分+线段树】
裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
随机推荐
- 在access转sql server指定的转换无效
今天继续昨天没解决的问题,还是继续报错数据库中“指定的转换无效”,看着这个错误都有点头大了,啊啊啊啊,因为无法再代码中寻找到具体点,只好在晚上继续查询 最后终于看到一条帖子说在转换的时候可能出现数据冲 ...
- Msi中文件替换
转自https://blog.csdn.net/davidhsing/article/details/9962377 ※说明:目前可以用于MSI编辑的软件很多,但是有些软件在保存时会在MSI文件中写入 ...
- JS 基础知识点
最近发现一个好东西,掘金小册,觉得里面的东西挺不错的,准备仔细阅读一下,提升下自己. 记录一下,随便加深点儿印象,主要内容源自于小册. 原始类型 原始类型也成为基本数据类型 boolean null ...
- 数据库设计很棒的参考CDM-PDM-LDM-PowerDesigner
此页面显示了涵盖主题领域的 50 个类别中的行业特定数据模型列表,用于创建企业数据模型. 以下是我们所有 1,700 多种数据模型的字母顺序列表 1. 广告 1. 顾客 1. 派对 1. 广告中 ...
- <TCP/IP原理> (二) OSI模型和TCP/IP协议族
1.OSI参考模型 1)作用 2)各层的名称和功能 2.对分层网络协议体系的理解 1)不同节点:层次组成不同,作用不同 2)横向理解:虚通信.对等实体.协议.PDU 3)纵向理解:封装与解封.服务.接 ...
- VUE项目中使用mint-ui框架总结
针对PC端,element-ui可谓是首选了,UI体验效果很好. element-ui 框架官网:http://element.eleme.io/#/zh-CN/component/installat ...
- linux 单用户密码修改
1.启动系统,并在GRUB2启动屏显时,按下e键进入编辑模式. 2.在linux16/inux/linuxef所在参数行ro更改为init=/sysroot/bin/sh 3.按Crl+x启动到she ...
- 在没联网环境下,启动tomcat出错
使用SSH框架,在联网情况下,项目可以正常运行,当一旦断网,则启动服务器报错: org.hibernate.HibernateException: Could not parse configurat ...
- java基于redis事务的秒杀实现
package com.vian.user.service; import org.junit.Test; import org.springframework.util.CollectionUtil ...
- Swift 之cannot load module 'main' as 'Swift'
如果建立一个Project, 选Command Line程序,语言选Swift, 完成之后会有一个main.swift文件.这个文件用来练算法最好了,因为playground会有各种限制而且bug多多 ...