SDOI_染色

背景:很早就想学习树链剖分,趁着最近有点自由安排的时间去学习一下,发现有个很重要的前置知识——线段树。(其实不一定是线段树,但是线段树应该是最常见的),和同学吐槽说树剖的剖和分都很死板,主要还是看线段树的维护功底。但是也要知道剖分完的结果,不然就算线段树玩得飞起,也维护不了。看了网上很多博客,都是说一个geth,一个mark完成树链剖分,然后映射到线段树上,进行维护,其实这只是一个大体思想,还是建议自己手动模拟一下去加深理解。

前置知识:
1、重儿子:hs[u]=v,表示vu的重儿子。意思是vu的儿子中子树规模(包括自己)最大的。
轻儿子:除了重儿子的其他儿子。
2、重链:由重儿子组成的链。
轻链:除了重链的其他链。
3、顶端结点:重链的开头。
说是重轻分解,其实实质是把重链揪出来(即从轻链处砍断连接关系)连在一起拼凑成区间(同一条重链上结点编号映射到数据结构上连续),用数据结构维护,也就是说把树变成由重链组成的,只剩下重链,不考虑轻链,对于映射,同一条重链中浅结点编号小。
个人觉得这句话很通俗易懂了。~

关于树链剖分:
首先:要是一棵树。。然后有几种剖分:1、随便剖分,爱怎么编号怎么编号。2、启发式剖分(也就是常见的重轻分解)。显然!2比较科学,随便的东西肯定不稳定,就算是不随便的也不一定稳定。。(基数排序最后倒数组时的for downto...就比for to.稳定,而正for显然不是随便的东西,我不会证明也一直没想明白,还望看官指点)。我们可以很简单的运用两次dfs完成对一棵树的剖分(第一次:geth,第二次:mark)。第一次主要是得到深度、父亲、规模、重儿子;第二次则是将同一条重链上的结点编号在一起,对应到线段树上。(rank[]、sa[] 这两个数组和在后缀数组中一样,因为不懂后缀数组,所以用这两个提醒自己还是个弱者),以及记录重链顶端结点。
其次:其实可以说,树链剖分的题,暴力求解就是树上倍增(跑LCA,然后沿途更新),那么如何优化?显然LCA肯定要跑,有没有办法跑得更快?答案是肯定的,树链的剖分就是让LCA跑得更快。显然对于V(u,v)要么在一条重链上,要么不在一条重链上。如果在一条重链上,深度浅的就是LCA,如果不在呢?不妨定义u为深度更深的结点,那么倍增的思想告诉我们应该把u跳到和v一样浅,然后一起跳。然而轻重分解直接把u跳到其所在重链顶端(期间维护和求解该链上的答案),判断u,v在不在一条重链上(tp[u]==tp[v]?),然后不断进行这个过程直到u,v在同一重链后运用数据结构维护求解。那么我们又知道了同一条重链新编号连续,那么进行区间维护就很方便了。
最后:看各位的线段树功底了,反正笔者的线段树是很差的。。
(PS:第一次看到给20s的题,有点刺激)


Code:

#pragma comment(linkerr, "/STACK: 1024000000,1024000000")
#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define eb emplace_back
#define em emplace
#define pii pair<int,int>
#define de(x) cout << #x << " = " << x << endl
#define clr(a,b) memset(a,b,sizeof(a))
#define INF (0x3f3f3f3f)
#define LINF ((long long)(0x3f3f3f3f3f3f3f3f))
#define F first
#define S second
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
using namespace std;const int N = 1e5 + 15;
int n, m;int d[N], fa[N], sz[N], hs[N];
int nw, sa[N], rk[N], tp[N];
struct Edge
{int v, nxt;
};
Edge e[N<<1];
int h[N], ect;
void init()
{ect = nw = 0;clr(h,-1);
}
void _add( int u, int v )
{e[ect].v = v;e[ect].nxt = h[u];h[u] = ect ++;
}void geth( int u, int f, int de )
{fa[u] = f;sz[u] = 1;hs[u] = 0;d[u] = de;for ( int i = h[u]; i+1; i = e[i].nxt ){int v = e[i].v;if ( v == f ) continue;geth( v, u, de+1 );sz[u] += sz[v];if ( sz[v] > sz[hs[u]] ) hs[u] = v;}
}
void mark( int u, int tu )
{tp[u] = tu;sa[++nw] = u; rk[u] = nw;if ( !hs[u] ) return ;mark( hs[u], tu );for ( int i = h[u]; i+1; i = e[i].nxt ){int v = e[i].v;if ( v != fa[u] && v != hs[u] ) mark(v,v);}
}struct T
{int sm, lazy, lc, rc;
};
T t[N<<2];
int A[N];
int nwlc, nwrc;void pushup( int rt )
{t[rt].sm = t[rt<<1].sm + t[rt<<1|1].sm;t[rt].lc = t[rt<<1].lc;t[rt].rc = t[rt<<1|1].rc;if ( t[rt<<1].rc == t[rt<<1|1].lc )t[rt].sm --;
}
void pushdown( int rt, int l, int r )
{if ( t[rt].lazy ){t[rt].lazy = 0;t[rt<<1].lazy = t[rt<<1|1].lazy = 1;t[rt<<1].sm = t[rt<<1|1].sm = 1;t[rt<<1].lc = t[rt<<1].rc = t[rt].lc;t[rt<<1|1].lc = t[rt<<1|1].rc = t[rt].rc;}
}void build( int rt, int l, int r )
{t[rt].lazy = 0;if ( l == r ){t[rt].sm = 1;t[rt].lc = t[rt].rc = A[sa[l]];return ;}int m = (l+r) >> 1;build(lson); build(rson); pushup(rt);
}void update( int L, int R, int c, int rt, int l, int r )
{if ( L <= l && r <= R ){t[rt].lc = t[rt].rc = c;t[rt].sm = t[rt].lazy = 1;return ;}int m = (l+r) >> 1;pushdown(rt,l,r);if ( L <= m ) update( L, R, c, lson );if ( R >  m ) update( L, R, c, rson );pushup(rt);
}int query( int L, int R, int rt, int l, int r )
{if ( L == l ) nwlc = t[rt].lc;if ( R == r ) nwrc = t[rt].rc;if ( L <= l && r <= R )return t[rt].sm;int m = (l+r) >> 1, res = 0, lft = 0;pushdown(rt,l,r);if ( L <= m ){lft = 1;res += query( L, R, lson );}if ( R >  m ){res += query( L, R, rson );if ( lft && t[rt<<1].rc == t[rt<<1|1].lc ) res --;}pushup(rt);return res;
}int getsum( int u, int v )
{int lstulc, lstvlc;lstulc = lstvlc = -1;int res = 0;int x = tp[u], y = tp[v];while ( x != y ){if ( d[x] < d[y] ) swap(x,y), swap(u,v), swap(lstulc,lstvlc);res += query( rk[x], rk[u], 1,1,n );if ( nwrc == lstulc ) res --;lstulc = nwlc;u = fa[x]; x = tp[u];}if ( d[u] > d[v] ) swap(u,v), swap( lstulc, lstvlc );res += query( rk[u], rk[v], 1,1,n );if ( nwlc == lstulc ) res --;if ( nwrc == lstvlc ) res --;return res;
}void change( int u, int v, int c )
{int x = tp[u], y = tp[v];while ( x != y ){if ( d[x] < d[y] ) swap(x,y), swap(u,v);update( rk[x], rk[u], c, 1,1,n );u = fa[x]; x = tp[u];}if ( d[u] > d[v] ) swap( u, v );update( rk[u], rk[v], c, 1,1,n );
}int main()
{init();scanf("%d%d", &n, &m);for ( int i = 1; i <= n; i ++ )scanf("%d", &A[i]);for ( int i = 1, u, v; i < n; i ++ ){scanf("%d%d", &u, &v);_add(u,v); _add(v,u);}geth(1,0,1);mark(1,1);build(1,1,n);while ( m -- ){char s[2];int u, v, c;scanf("%s %d%d", s, &u, &v);if ( s[0] == 'C' ){scanf("%d", &c);change( u, v, c );}elseprintf("%d\n", getsum(u,v));}return 0;
}

转载于:https://www.cnblogs.com/FormerAutumn/p/10212543.html

SDOI2011_染色相关推荐

  1. [C] 深度优先搜索解决连通块/染色问题——求岛的个数

    本文介绍用DFS解决连通块个数问题 有关dfs的介绍见另外一篇:不撞南墙不回头--深度优先搜索 例题 宝岛探险 题目描述 一个小岛由一个主岛和一些复附属岛屿组成,该岛使用一个二维矩阵表示,其中数字表示 ...

  2. [BZOJ4033][HAOI2015]树上染色

    4033: [HAOI2015]树上染色 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 2108  Solved: 901 [Submit][Sta ...

  3. 2-sat问题,输出方案,几种方法(赵爽的论文染色解法+其完全改进版)浅析 / POJ3683...

    本文原创于  2014-02-12 09:26. 今复习之用,有新体会,故重新编辑. 2014-02-12 09:26: 2-sat之第二斩!昨天看了半天论文(赵爽的和俉昱的),终于看明白了!好激动有 ...

  4. 【Codeforces】1080C Masha and two friends (棋盘染色)

    http://codeforces.com/problemset/problem/1080/C 给定一个棋盘,(1,1)的位置是白色,观察可以知道,如果横纵坐标之和是偶数,那么是白色,奇数的话就是黑色 ...

  5. Luogu P3177 [HAOI2015] 树上染色(树上背包)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Luogu P3177 [HAOI2015] 树上染色 有一棵点数为 NNN 的树,树边有边权.给你一 ...

  6. UVA1364 Knights of the Round Table(双连通分量、二分图染色,超详细解释)

    整理的算法模板合集: ACM模板 UVA1364 Knights of the Round Table 题目中要求互相有憎恨关系的人不能坐在相邻的位置,一个圆桌可以很形象地看作是一个环,也就是说我们两 ...

  7. P3196 [HNOI2008]神奇的国度(弦图的最小染色问题)

    整理的算法模板合集: ACM模板 题目传送门 K国是一个热衷三角形的国度,连人的交往也只喜欢三角原则.他们认为三角关系:即AB相互认识,BC相互认识,CA相互认识,是简洁高效的.为了巩固三角关系,K国 ...

  8. AT2362 [AGC012B] Splatter Painting(思维、dfs染色、剪枝)

    AT2362 [AGC012B] Splatter Painting 题意 给一个n个点m条边的无向图,有q次操作 第i次操作,给出v,d,c,把所有到点v的距离不超过d的点都染上颜色c 问最后每个点 ...

  9. P1155 双栈排序(二分图的染色判断+链式前向星)

    P1155 双栈排序 让字典序最小,当然尽量进S1 那什么时候必须进S2呢? a[i]和a[j] 不能压入同一个栈⇔存在一个k,使得i<j<k且a[k]<a[i]<a[j] 因 ...

最新文章

  1. VSCode设置折叠左侧资源管理器所有文件夹的快捷键Alt+X、切换左侧活动栏显示隐藏快捷键Alt+Q
  2. C++赋值运算符与赋值表达式
  3. python3+django写的个人笔记博客
  4. python入门指南bl-Python Matplotlib 绘图使用指南 (附代码)
  5. 快速排序的实现及优化
  6. linux命令:mkdir命令
  7. SRTP参数及数据包处理过程
  8. Bad Hair Day(POJ-3250)
  9. leetcode—— 401. 二进制手表(使用到将数字转换为字符)
  10. 计算机设备 运维,计算机网络设备运维报告
  11. 推荐系统走向下一阶段最重要的三个问题
  12. mysql 字符串枚举类型转换_MyBatis里字段到枚举类型的转换/映射
  13. 四行代码创建复杂(无限级)树
  14. RenderTransformOrigin 的作用
  15. 在Vue.js中使用Mixin
  16. 用fft对信号进行频谱分析实验报告_频谱分析之Analyzer软件分析
  17. 小福利,PMP考试真题刷起来,人人都当项目管理大师!
  18. 通过相关系数和自由度求置信度
  19. photoshop使用技巧_你应该知道的45个聪明的Photoshop技巧
  20. 映射网络驱动器错误:无法找到网络名,该设备或资源未设置为接受端口,“文件和打印机共享(SMB)”上的连接。

热门文章

  1. Git使用问题:You asked to pull from the remote 'origin', but did not specify a branch......
  2. Spring、Spring MVC、Spring boot、Spring Cloud面试题(史上最全面试题,精心整理100家互联网企业,面试必过)
  3. Android 序列化(Serializable和Parcelable),android开发板底层开发
  4. 向大院大所要智慧——江苏创新转型扫描
  5. 持续集成与持续部署(三)——实现持续集成的效率工具对比之Jenkins、Travis CI、Circle CI和其他持续集成工具
  6. 红枣的尺寸外观缺陷视觉检测是如何进行的
  7. Ec/Io____C/I
  8. Python之PySerial串口通信
  9. 计算机专硕和学硕工作,研究生上完想直接工作,我该选择学硕还是专硕
  10. NVIDIA公布2019财年财报,营收大幅下跌,利润腰斩