博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ2243 洛谷2486 [SDOI2011]染色 树链剖分
阅读量:5152 次
发布时间:2019-06-13

本文共 3362 字,大约阅读时间需要 11 分钟。

欢迎访问~原文出处——



题意概括

  一棵树,共n个节点。

  让你支持以下两种操作,共m次操作:

  1. 区间染色:给定两个节点,让你给树中链接这两个节点的路径染色。

  2. 区间询问:给定两个节点,让你求出连接这两个节点的路径的色段数。比如说"112221"就是3段,分别是"11" "222" "1"

  一开始给出初始染色情况。

  n<=100000,m<=100000


题解

  首先树链剖分,很明显。

  然后线段树维护区间颜色。

  我们可以写一个结构体,方便色段操作。

  结构体保存4个值:当前色段的颜色总数v,左端和右端颜色:L,R;以及一个标记add:对于线段树,可以用作lazy标记,而对于色段的求和,可以用作空色段的标记(-2);

  那么色段相加就可以也一个运算符重载。这样很方便。

struct Tree{	int add,v,L,R;	Tree (){}	Tree (int x,int a,int b,int c){		add=x,v=a,L=b,R=c;	}}t[N*4];Tree operator + (Tree a,Tree b){	if (a.add==-2)		return b;	if (b.add==-2)		return a;	return Tree(-1,a.v+b.v-(a.R==b.L),a.L,b.R);}

  然后就是线段树的维护了。

  维护很简单,add标记打一打就可以了。

  查询也很简单。反正空颜色段为(-2,0,0,0),合并结果就是把两个色段加起来。

  对于在树上取多段链,首先对于两个纵向的链我们求出色段。

  然后最终两个点会到同一条链上。(如果没看懂这个,那么您还得重新学学树剖)

  然后随便选一个色段翻转一下(你喜欢那个就那个,比如我翻转了上面的那个),然后再求出这两个点之间的色段,全部加起来就可以了。


代码

#include 
#include
#include
#include
#include
using namespace std;const int N=100005;struct Gragh{ int cnt,y[N*2],nxt[N*2],fst[N]; void clear(){ cnt=0; memset(fst,0,sizeof fst); } void add(int a,int b){ y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt; }}g;struct Tree{ int add,v,L,R; Tree (){} Tree (int x,int a,int b,int c){ add=x,v=a,L=b,R=c; }}t[N*4];Tree operator + (Tree a,Tree b){ if (a.add==-2) return b; if (b.add==-2) return a; return Tree(-1,a.v+b.v-(a.R==b.L),a.L,b.R);}int n,m,v[N],fa[N],size[N],depth[N],son[N],top[N],p[N],ap[N],cnp;void Get_Gen_Info(int rt,int pre,int d){ fa[rt]=pre,size[rt]=1,son[rt]=-1,depth[rt]=d; for (int i=g.fst[rt];i;i=g.nxt[i]) if (g.y[i]!=pre){ int s=g.y[i]; Get_Gen_Info(s,rt,d+1); size[rt]+=size[s]; if (son[rt]==-1||size[s]>size[son[rt]]) son[rt]=s; }}void Get_Pos(int rt,int tp){ top[rt]=tp,p[rt]=++cnp,ap[cnp]=rt; if (son[rt]==-1) return; else Get_Pos(son[rt],tp); for (int i=g.fst[rt];i;i=g.nxt[i]){ int s=g.y[i]; if (s!=son[rt]&&s!=fa[rt]) Get_Pos(s,s); }}void pushup(int rt){ t[rt]=t[rt<<1]+t[rt<<1|1];}void build(int rt,int le,int ri){ t[rt].add=-1; if (le==ri){ t[rt].L=t[rt].R=v[ap[le]]; t[rt].v=1; return; } int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1; build(ls,le,mid); build(rs,mid+1,ri); pushup(rt);}void pushdown(int rt){ int ls=rt<<1,rs=ls|1; int &a=t[rt].add; if (a==-1) return; t[ls].L=t[rs].L=t[ls].R=t[rs].R=a; t[ls].v=t[rs].v=1; t[ls].add=t[rs].add=a; a=-1;}void update(int rt,int le,int ri,int xle,int xri,int v){ if (ri
xri) return; if (xle<=le&&ri<=xri){ t[rt].add=t[rt].L=t[rt].R=v; t[rt].v=1; return; } pushdown(rt); int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1; update(ls,le,mid,xle,xri,v); update(rs,mid+1,ri,xle,xri,v); pushup(rt);}Tree query(int rt,int le,int ri,int xle,int xri){ if (ri
xri) return Tree(-2,0,0,0); if (xle<=le&&ri<=xri) return t[rt]; pushdown(rt); int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1; return query(ls,le,mid,xle,xri)+query(rs,mid+1,ri,xle,xri);}void Tupdate(int a,int b,int c){ int f1=top[a],f2=top[b]; while (f1!=f2){ if (depth[f1]
depth[b]) swap(a,b); update(1,1,n,p[a],p[b],c);}int solve(int a,int b){ int f1=top[a],f2=top[b]; Tree r1(-2,0,0,0),r2(-2,0,0,0); while (f1!=f2){ if (depth[f1]
depth[b]) swap(a,b),swap(r1,r2); swap(r1.L,r1.R); return (r1+query(1,1,n,p[a],p[b])+r2).v;}int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&v[i]); g.clear(); for (int i=1,a,b;i

  

 

转载于:https://www.cnblogs.com/zhouzhendong/p/BZOJ2243.html

你可能感兴趣的文章
Android开发技术周报 Issue#80
查看>>
hadoop2.2.0+hive-0.10.0完全分布式安装方法
查看>>
django知识点总结
查看>>
C++ STL stack、queue和vector的使用
查看>>
使用Reporting Services时遇到的小问题
查看>>
约瑟夫问题
查看>>
Arduino 报错总结
查看>>
树莓派Android Things物联网开发:树莓派GPIO引脚图
查看>>
矩阵快速幂---BestCoder Round#8 1002
查看>>
js兼容公用方法
查看>>
如何将应用完美迁移至Android P版本
查看>>
【转】清空mysql一个库中的所有表的数据
查看>>
基于wxPython的python代码统计工具
查看>>
淘宝JAVA中间件Diamond详解(一)---简介&快速使用
查看>>
Hadoop HBase概念学习系列之HBase里的宽表设计概念(表设计)(二十七)
查看>>
Kettle学习系列之Kettle能做什么?(三)
查看>>
Day03:Selenium,BeautifulSoup4
查看>>
awk变量
查看>>
mysql_对于DQL 的简单举例
查看>>
35. Search Insert Position(C++)
查看>>