HYSBZ 2243 染色 树链剖分
2016-05-15 17:38
465 查看
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2243
题意:
Description
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
Input
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
Output
对于每个询问操作,输出一行答案。
思路:线段树区间更新区间合并,好麻烦。。。
总结:目前我写过的最长的代码。。。大概因为写的复杂题太少了
题意:
Description
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
Input
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
Output
对于每个询问操作,输出一行答案。
思路:线段树区间更新区间合并,好麻烦。。。
总结:目前我写过的最长的代码。。。大概因为写的复杂题太少了
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 100100; struct edge { int to, next; }g[N*2]; int dep , siz , son , fat , id , top , head ; int tmp , d [2], val ; int n, m, num, cnt; struct node { int l, r, lc, rc, sum, mark; /*lc, rc记录区间左端点和右端点颜色,*/ }s[N*4]; void add_edge(int v, int u) { g[cnt].to = u; g[cnt].next = head[v]; head[v] = cnt++; } void dfs1(int v, int fa, int d) { dep[v] = d, son[v] = 0, siz[v] = 1, fat[v] = fa; for(int i = head[v]; i != -1; i = g[i].next) { int u = g[i].to; if(u != fa) { dfs1(u, v, d + 1); siz[v] += siz[u]; if(siz[son[v]] < siz[u]) son[v] = u; } } } void dfs2(int v, int tp) { top[v] = tp, id[v] = ++num; if(son[v]) dfs2(son[v], top[v]); for(int i = head[v]; i != -1; i = g[i].next) { int u = g[i].to; if(u != fat[v] && u != son[v]) dfs2(u, u); } } void push_up(int k) /*区间合并,判断左儿子的右端点和右儿子的左端点是否相同,更新父节点左右端点颜色*/ { s[k].lc = s[k<<1].lc, s[k].rc = s[k<<1|1].rc; if(s[k<<1].rc == s[k<<1|1].lc) s[k].sum = s[k<<1].sum + s[k<<1|1].sum - 1; else s[k].sum = s[k<<1].sum + s[k<<1|1].sum; } void push_down(int k) { if(s[k].mark) { s[k<<1].mark = s[k<<1|1].mark = s[k].mark; s[k<<1].lc = s[k<<1].rc = s[k<<1|1].lc = s[k<<1|1].rc = s[k].mark; s[k<<1].sum = s[k<<1|1].sum = 1; s[k].mark = 0; } } void build(int l, int r, int k) { s[k].l = l, s[k].r = r, s[k].sum = 1, s[k].mark = 0; if(l == r) { s[k].lc = s[k].rc = val[l]; return; } int mid = (l + r) >> 1; build(l, mid, k << 1); build(mid + 1, r, k << 1|1); push_up(k); } void update(int l, int r, int c, int k) { if(l <= s[k].l && s[k].r <= r) { s[k].sum = 1; s[k].lc = s[k].rc = c; s[k].mark = c; return; } push_down(k); int mid = (s[k].l + s[k].r) >> 1; if(l <= mid) update(l, r, c, k << 1); if(r > mid) update(l, r, c, k << 1|1); push_up(k); } void renew(int v, int u, int c) { int t1 = top[v], t2 = top[u]; while(t1 != t2) { if(dep[t1] < dep[t2]) swap(t1, t2), swap(v, u); update(id[t1], id[v], c, 1); v = fat[t1], t1 = top[v]; } if(dep[v] > dep[u]) swap(v, u); update(id[v], id[u], c, 1); } int query(int l, int r, int k) { if(l <= s[k].l && s[k].r <= r) return s[k].sum; push_down(k); int mid = (s[k].l + s[k].r) >> 1; int ans = 0, f1 = 0, f2 = 0; if(l <= mid) ans += query(l, r, k << 1), f1 = 1; if(r > mid) ans += query(l, r, k << 1|1), f2 = 1; if(f1 && f2) /*查询时注意判断相邻两个区间相接处颜色是否相同*/ if(s[k<<1].rc == s[k<<1|1].lc) ans -= 1; push_up(k); return ans; } int query_node(int x, int k) { if(s[k].l == s[k].r) return s[k].rc; push_down(k); int mid = (s[k].l + s[k].r) >> 1; int ans = 0; if(x <= mid) ans = query_node(x, k << 1); else ans = query_node(x, k << 1|1); push_up(k); return ans; } int seek(int v, int u) { int t1 = top[v], t2 = top[u]; int ans = 0; while(t1 != t2) { if(dep[t1] < dep[t2]) swap(t1, t2), swap(v, u); ans += query(id[t1], id[v], 1); /*判断相邻两个区间相接处颜色是否相同*/ if(query_node(id[t1], 1) == query_node(id[fat[t1]], 1)) ans--; v = fat[t1], t1 = top[v]; } //printf("%d\n", ans); if(dep[v] > dep[u]) swap(v, u); return ans += query(id[v], id[u], 1); } void slove() { char ch; int a, b, c; while(m--) { scanf(" %c", &ch); if(ch == 'Q') { scanf("%d%d", &a, &b); printf("%d\n", seek(a, b)); } else { scanf("%d%d%d", &a, &b, &c); renew(a, b, c); } } } int main() { while(~ scanf("%d%d", &n, &m)) { memset(head, -1, sizeof head); cnt = num = 0; for(int i = 1; i <= n; i++) scanf("%d", tmp + i); for(int i = 1; i <= n - 1; i++) { scanf("%d%d", &d[i][0], &d[i][1]); add_edge(d[i][0], d[i][1]); add_edge(d[i][1], d[i][0]); } dfs1(1, 0, 1); dfs2(1, 1); for(int i = 1; i <= n; i++) val[id[i]] = tmp[i]; build(1, num, 1); slove(); } return 0; }
相关文章推荐
- 机器学习那些事
- 包含min函数的栈
- Java方法参数传递
- Android Studio 快捷键使用
- 队列的两种存储结构
- C++——C/C++static关键字
- JavaWeb学习总结(1)------JavaWeb开发入门
- 日志轮询的小脚本
- iOS中assign,copy,retain之间的区别以及weak和strong的区别
- 利用Python3在Windows同步文件到Linux服务器
- 华中农业大学预赛
- 学习进度第十一周
- Intellij Idea系列之Tomcat环境的搭建(三)
- fastjson使用示例
- MyBatis的动态SQL详解
- 被动信息收集:信息收集内容、信息用途、信息收集DNS、DNS信息收集-NSLOOKUP
- cookie读写JS
- (三)maven出错记录
- <css3>border
- MFC判断Listctrl当前选中的单元格的行和列