树链剖分——线段树区间合并bzoj染色
线段树区间合并就挺麻烦了,再套个树链就更加鬼畜,不过除了代码量大就没什么其他的了。。
一些细节:线段树每个结点用结构体保存,pushup等合并函数改成返回一个结构体,这样好写一些
struct Seg{int lc,rc,tot;Seg(){lc=rc=-1;tot=0;} }; Seg seg[maxn<<2];int lazy[maxn<<2]; 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],1,n,1),B);y=f[top[y]]; }else {A=pushup(query(id[top[x]],id[x],1,n,1),A);x=f[top[x]];}}if(id[x]>id[y])A=pushup(query(id[y],id[x],1,n,1),A);else B=pushup(query(id[x],id[y],1,n,1),B);if(A.lc==B.lc)return A.tot+B.tot-1;else return A.tot+B.tot; }
最后是完整代码
#include<bits/stdc++.h> using namespace std; #define maxn 100005 struct Edge{int to,nxt;}edge[maxn<<1]; 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]=1,d[x]=deep;for(int i=head[x];i!=-1;i=edge[i].nxt){int y=edge[i].to;if(y==pre)continue;f[y]=x;dfs1(y,x,deep+1);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!=-1;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=-1;tot=0;} }; Seg seg[maxn<<2];int lazy[maxn<<2]; 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]<0)return; lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];seg[rt<<1].lc=seg[rt<<1].rc=lazy[rt];seg[rt<<1].tot=1;seg[rt<<1|1].lc=seg[rt<<1|1].rc=lazy[rt];seg[rt<<1|1].tot=1;lazy[rt]=-1; } void build(int l,int r,int rt){if(l==r){seg[rt].lc=seg[rt].rc=c[rk[l]];seg[rt].tot=1;return;}int m=l+r>>1;build(lson);build(rson);seg[rt]=pushup(seg[rt<<1],seg[rt<<1|1]); } 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=1;return;}pushdown(rt);int m=l+r>>1;if(L<=m)update(L,R,c,lson);if(R>m)update(L,R,c,rson);seg[rt]=pushup(seg[rt<<1],seg[rt<<1|1]); } 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>>1;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,1,n,1);x=f[top[x]];}if(id[x]>id[y])swap(x,y);update(id[x],id[y],c,1,n,1); } 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],1,n,1),B);y=f[top[y]]; }else {A=pushup(query(id[top[x]],id[x],1,n,1),A);x=f[top[x]];}}if(id[x]>id[y])A=pushup(query(id[y],id[x],1,n,1),A);else B=pushup(query(id[x],id[y],1,n,1),B);if(A.lc==B.lc)return A.tot+B.tot-1;else return A.tot+B.tot; }void init(){memset(head,-1,sizeof head);memset(lazy,-1,sizeof lazy);tot=0; } 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=1;i<=n;i++)cin>>c[i];for(int i=1;i<n;i++){int x,y;cin>>x>>y;addedge(x,y);addedge(y,x);}cnt=0;dfs1(1,0,1),dfs2(1,1);build(1,n,1);char op[2];int x,y,z;while(q--){scanf("%s",op);if(op[0]=='Q'){scanf("%d%d",&x,&y);cout<<Query(x,y)<<'\n';}if(op[0]=='C'){scanf("%d%d%d",&x,&y,&z);Update(x,y,z);}} }
View Code
转载于:https://www.cnblogs.com/zsben991126/p/10759166.html
树链剖分——线段树区间合并bzoj染色相关推荐
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MB Submit: 1153 Solved: 421 [Submit][Sta ...
- P2486 [SDOI2011]染色(树链剖分+线段树)
题干描述 输入描述 输出格式 对于每个询问操作,输出一行答案. 输入输出样例 输入 #1 复制 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树
题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...
- CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)
题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...
- BZOJ4127Abs——树链剖分+线段树
题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...
- BZOJ3862Little Devil I——树链剖分+线段树
题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...
- CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)
题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...
- HDU 2460 Network(双连通+树链剖分+线段树)
HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...
- YbtOJ-染色计划【树链剖分,线段树,tarjan】
正题 题目大意 给出nnn个点的一棵树,每个点有个颜色aia_iai,你每次可以选择一个颜色全部变成另一个颜色. 求最少多少次操作可以把一种颜色变成一个完整的连通块. 1≤k≤n≤2×1051\le ...
最新文章
- framebuffer的入门介绍-实现程序分析【转】
- Windows python用impyla连接远程Hive数据库
- ICCV 2019 运行LCGN遇到的问题及解决办法
- netsh 查询mac地址_ARP(Address Resolution Protocol)地址解析协议
- Android之录音--AudioRecord、MediaRecorder
- [EDA] 2.2 简单PLD结构原理-潘松版
- 事务失败返回_什么是分布式事务以及有哪些解决方案?
- python安装轮子_自己动手造“轮子”---python常用的几个方法
- ras私钥c#转java_RSA密钥,JAVA与.NET之间转换
- Android 自定义AlertDialog对话框
- big sur支持机型_小米10 Pro官方下架:高端在售机型只剩它
- 时间linux防火墙策略,Linux防火墙简介 – iptables配置策略(示例代码)
- Tuxedo中间件开发和管理
- cydia多开微信_苹果ios怎么多开微信分身?
- Java性能优化的35种方法
- ImageMagick (Magick++ for C++) configuration in Visual Studio 2012
- 【尚硅谷_数据结构与算法】一、数据结构与算法概述
- 金融信创云:从遥不可及到价值担当
- tf.ones_like()函数用法详解(附代码理解)
- matlab n次贝塞尔曲线