题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2243

线段树+树链剖分,在线段树需要每次用lt和rt两个数组记录当前区间的左右边界的颜色,向上更新时需要判断左区间的右边界是否和右区间的左边界相等。在剖分求LCA的过程中需要在求值之后查询与下一次求值的边界是否相等。

 #include<bits/stdc++.h>
#define lson l,mid,i<<1
#define rson mid+1,r,i<<1|1
using namespace std;
typedef long long ll;
const int maxn = ;
const int INF = 2e9;
struct node {
int s, e, next;
}edge[maxn * ];
int n, m;
int son[maxn], top[maxn], tid[maxn], fat[maxn], siz[maxn], dep[maxn], rak[maxn];
int head[maxn], len, dfx;
//siz保存以i为根的子树节点个数,top保存i节点所在链的顶端节点,son保存i节点的重儿子,fat保存i节点的父亲节点
//dep保存i节点的深度(根为1),,tid保存i节点dfs后的新编号,rak保存新编号i对应的节点(rak[i]=j,tid[j]=i)。
void init() {
memset(head, -, sizeof(head));
len = , dfx = ;
}
void add(int s, int e) {//邻接表存值
edge[len].s = s;
edge[len].e = e;
edge[len].next = head[s];
head[s] = len++;
}
//搜出每个节点的siz,son,fat,dep
void dfs1(int x, int fa, int d) {
siz[x] = , son[x] = -, fat[x] = fa, dep[x] = d;
for (int i = head[x]; i != -; i = edge[i].next) {
int y = edge[i].e;
if (y == fa)
continue;
dfs1(y, x, d + );
siz[x] += siz[y];
if (son[x] == - || siz[y] > siz[son[x]])
son[x] = y;
}
}
//搜出每个节点的top,tid,rak
void dfs2(int x, int c) {
top[x] = c;
tid[x] = ++dfx;
rak[dfx] = x;
if (son[x] == -)
return;
dfs2(son[x], c);
for (int i = head[x]; i != -; i = edge[i].next) {
int y = edge[i].e;
if (y == fat[x] || y == son[x])
continue;
dfs2(y, y);
}
}
int a[maxn];
int cr[maxn * ];
int rt[maxn * ];
int lt[maxn * ];
int lazy[maxn * ];
void up(int i) {
lt[i] = lt[i << ], rt[i] = rt[i << | ];
cr[i] = cr[i << ] + cr[i << | ];
if (lt[i << | ] == rt[i << ])
cr[i]--;
}
void down(int i) {
if (lazy[i] != -) {
lt[i << ] = lt[i << | ] = rt[i << ] = rt[i << | ] = lazy[i];
cr[i << ] = cr[i << | ] = cr[i];
lazy[i << ] = lazy[i << | ] = lazy[i];
lazy[i] = -;
}
}
void build(int l, int r, int i) {
lazy[i] = -;
if (l == r) {
cr[i] = ;
rt[i] = a[rak[l]];
lt[i] = a[rak[l]];
return;
}
int mid = (l + r) >> ;
build(lson);
build(rson);
up(i);
}
void update(int L, int R, int k, int l, int r, int i) {
if (L <= l && r <= R) {
cr[i] = ;
lazy[i] = k;
lt[i] = rt[i] = k;
return;
}
down(i);
int mid = (l + r) >> ;
if (L <= mid)
update(L, R, k, lson);
if (R > mid)
update(L, R, k, rson);
up(i);
}
int qquery(int L, int R, int l, int r, int i) {
if (L <= l && r <= R) return cr[i];
down(i);
int mid = (l + r) >> ;
if (R <= mid) return qquery(L, R, lson);
if (L > mid) return qquery(L, R, rson);
int ans1 = qquery(L, R, lson);
int ans2 = qquery(L, R, rson);
int ans = ans1 + ans2;
if (rt[i << ] == lt[i << | ]) ans--;
return ans;
} int dquery(int k, int l, int r, int i) {
if (l == r) {
return lt[i];
}
int mid = (l + r) / ;
down(i);
if (k <= mid)
return dquery(k, lson);
else
return dquery(k, rson);
}
int solve(int x, int y, int w, int flg) {
int ans = ;
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]])
swap(x, y);
if (!flg)
update(tid[top[x]], tid[x], w, , n, );
else {
ans += qquery(tid[top[x]], tid[x], , n, );
if (dquery(tid[top[x]], , n, ) == dquery(tid[fat[top[x]]], , n, ))
ans--;
}
x = fat[top[x]];
}
if (dep[x] < dep[y])
swap(x, y);
if (!flg)
update(tid[y], tid[x], w, , n, );
else {
ans += qquery(tid[y], tid[x], , n, );
return ans;
}
}
int main() {
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = ; i <= n; i++)
scanf("%d", &a[i]);
init();
int x, y, z;
for (int i = ; i < n - ; i++) {
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
dfs1(, , );
dfs2(, );
build(, n, );
while (m--) {
char s[];
scanf("%s", s);
if (s[] == 'C') {
scanf("%d%d%d", &x, &y, &z);
solve(x, y, z, );
}
else {
scanf("%d%d", &x, &y);
printf("%d\n", solve(x, y, , ));
}
}
}
}

LCT的做法好像更简明,只不过down的时候记得交换lv和rv.

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = ;
ll fa[maxn], ch[maxn][], siz[maxn], val[maxn], sum[maxn], lv[maxn], rv[maxn], lazy2[maxn], lazy[maxn], st[maxn];//父亲节点,左右儿子节点,当前子数节点个数,当前值,lazy标记,辅助数组。
inline bool isroot(int x) {//判断x是否为所在splay的根
return ch[fa[x]][] != x && ch[fa[x]][] != x;
}
inline void pushup(int x) {
lv[x] = ch[x][] ? lv[ch[x][]] : val[x];
rv[x] = ch[x][] ? rv[ch[x][]] : val[x];
if (ch[x][] && ch[x][])sum[x] = sum[ch[x][]] + sum[ch[x][]] + - (rv[ch[x][]] == val[x]) - (lv[ch[x][]] == val[x]);
else if (ch[x][])sum[x] = sum[ch[x][]] + (rv[ch[x][]] != val[x]);
else if (ch[x][])sum[x] = sum[ch[x][]] + (lv[ch[x][]] != val[x]);
else sum[x] = ;
siz[x] = siz[ch[x][]] + siz[ch[x][]] + ;
}
inline void pushr(int x) {
swap(ch[x][], ch[x][]);
swap(lv[x], rv[x]);
lazy[x] ^= ;
}
inline void pushC(int x, int c) {
val[x] = lv[x] = rv[x] = c, sum[x] = ;
lazy2[x] = c;
}
inline void pushdown(int x) {
if (lazy[x]) {
if (ch[x][])lazy[ch[x][]] ^= ;
if (ch[x][])lazy[ch[x][]] ^= ;
swap(ch[x][], ch[x][]);
lazy[x] = ;
}
if (lazy2[x]) {
if (ch[x][])pushC(ch[x][], lazy2[x]);
if (ch[x][])pushC(ch[x][], lazy2[x]);
lazy2[x] = ;
}
}
inline void rotate(int x) {
int y = fa[x], z = fa[y];
int k = ch[y][] == x;
if (!isroot(y))
ch[z][ch[z][] == y] = x;
fa[x] = z; ch[y][k] = ch[x][k ^ ]; fa[ch[x][k ^ ]] = y;
ch[x][k ^ ] = y; fa[y] = x;
pushup(y);
pushup(x);
}
inline void splay(int x) {
int f = x, len = ;
st[++len] = f;
while (!isroot(f))st[++len] = f = fa[f];
while (len)pushdown(st[len--]);
while (!isroot(x)) {
int y = fa[x];
int z = fa[y];
if (!isroot(y))
rotate((ch[y][] == x) ^ (ch[z][] == y) ? x : y);
rotate(x);
}
pushup(x);
}
inline void access(int x) {//打通根节点到x的实链
for (int y = ; x; x = fa[y = x])
splay(x), ch[x][] = y, pushup(x);
}
inline void makeroot(int x) {//将x变为原树的根
access(x); splay(x); pushr(x);
}
int Findroot(int x) {//找根节点
access(x), splay(x);
while (ch[x][])
pushdown(x), x = ch[x][];
splay(x);
return x;
}
inline void split(int x, int y) {//将x到y路径变为play
makeroot(x); access(y); splay(y);
}
inline void Link(int x, int y) {//合法连边
makeroot(x); fa[x] = y;
}
inline void cut(int x, int y) {//合法断边
split(x, y); fa[x] = ch[y][] = ; pushup(y);
}
int main() {
int n, q;
scanf("%d%d", &n, &q);
for (int i = ; i <= n; i++)
scanf("%d", &val[i]), lv[i] = rv[i] = val[i], sum[i] = ;
int x, y, z;
for (int i = ; i < n; i++) {
scanf("%d%d", &x, &y);
Link(x, y);
}
while (q--) {
char s[];
scanf("%s", s);
if (s[] == 'Q') {
scanf("%d%d", &x, &y);
split(x, y);
printf("%d\n", sum[y]);
}
else {
scanf("%d%d%d", &x, &y, &z);
split(x, y);
pushC(y, z);
}
}
}

[Bzoj2243][SDOI2011]染色(线段树&&树剖||LCT)的更多相关文章

  1. bzoj2243: [SDOI2011]染色--线段树+树链剖分

    此题代码量较大..但是打起来很爽 原本不用lca做一直wa不知道为什么.. 后来改lca重打了一遍= =结果一遍就AC了orz 题目比较裸,也挺容易打,主要是因为思路可以比较清晰 另:加读入优化比没加 ...

  2. [BZOJ2243][SDOI2011]染色 解题报告|树链剖分

    Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“ ...

  3. BZOJ2243 SDOI2011 染色 【树链剖分】

    BZOJ2243 SDOI2011 染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色 ...

  4. bzoj2243[SDOI2011]染色 树链剖分+线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9012  Solved: 3375[Submit][Status ...

  5. bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 7925  Solved: 2975[Submit][Status ...

  6. 洛谷$P2486\ [SDOI2011]$染色 线段树+树链剖分

    正解:线段树+树链剖分 解题报告: 传送门$QwQ$ 其实是道蛮板子的题,,,但因为我写得很呆然后写了贼久之后发现想法有问题要重构,就很难受,就先写个题解算了$kk$ 考虑先跑个树剖,然后按$dfn$ ...

  7. 【树链剖分】bzoj2243 [SDOI2011]染色

    树链剖分模板题.线段树维护每个段中的颜色数.左端点颜色.右端点颜色. pushup: col[rt]=col[rt<<1]+col[rt<<1|1]-(Rcol[rt<& ...

  8. BZOJ2243: [SDOI2011]染色(树链剖分/LCT)

    Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如 ...

  9. BZOJ2243[SDOI2011]染色——树链剖分+线段树

    题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如“112221 ...

随机推荐

  1. FCKEditor报java.lang.NullPointerException

    1.需要在 加value=“ ” <FCK:editor instanceName="replycontent" basePath="/fckeditor" ...

  2. Car的旅行路线(Floyd+模拟)

    题目地址 贼鸡儿猥琐的一道题 好在数据不毒瘤,而且Floyd就OK了. 这道题的难点在于 建图,也很考验模拟能力,需要十分的有耐心. 建图 题目中告诉了我们一个矩形的三个点 我们在平面直角坐标系中随便 ...

  3. 3.xml的解析

    1.xml的解析原理简介(xml是标记型文档) (1)js使用dom解析标记型文档(html)? - 根据html的层级结构,在内存中分配一个树形结构,把html的标签,属性和文本都封装成对象 - d ...

  4. Zabbix分布式监控系统实践 自定义配置

    https://www.zabbix.com/wiki/templates/start 环境介绍OS: Ubuntu 10.10 Server 64-bitServers:zabbix-server: ...

  5. mitmproxy 使用mitmdump 过滤请求

    mitmproxy 抓包工具,优点可以使用python进行二次开发,或者进行接口的mock 官网地址:https://www.mitmproxy.org/ 打算用这个最初的需求是,想对app做接口测试 ...

  6. 分享一个知乎答案 最详细易懂的 js闭包

    作者:大闲人柴毛毛 链接:https://www.zhihu.com/question/34210214/answer/136673471 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非 ...

  7. 基于 Flink 的实时数仓生产实践

    数据仓库的建设是“数据智能”必不可少的一环,也是大规模数据应用中必然面临的挑战.在智能商业中,数据的结果代表了用户反馈.获取数据的及时性尤为重要.快速获取数据反馈能够帮助公司更快地做出决策,更好地进行 ...

  8. php中substr_compare()区分大小写吗

    PHP substr_compare() 函数 定义和用法 substr_compare() 函数从指定的开始位置比较两个字符串. 提示:该函数是二进制安全且选择性地对大小写敏感(区分大小写). 语法 ...

  9. ubantu elasticsearch服务搭建

    1.jdk 1.8以上,elasticsearch是java开发的 [root@VM_58_118_centos sgconfig]# java -version java version " ...

  10. idea2019.2 svn 忽略文件问题

    自己用的是idea2019.2最新版本,今天提交的时候Commit Changes Dialog local changes refresh一直再刷新 其他的方法都是老版本都不适合 解决办法 找到Se ...