题目链接: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. vue访问外部接口设置代理,解决跨域(vue-cli3.0)

    vue-cli3.0搭建的项目,平时访问内部接口配置了拦截器,今天需要调用天气预报的外部接口,发现跨域问题,通过配置代理解决. 1.在vue.config.js中配置代理 module.exports ...

  2. FCKEditor报java.lang.NullPointerException

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

  3. image按钮新增的width属性和height属性

    代码实例: test.html <!DOCTYPE html> <html lang="en"> <head> <meta charset ...

  4. Spring Aop 动态代理失效分析

    1. Spring Aop 原理 Spring Aop 通过动态代理创建代理对象,在调用代理对象方法前后做增强. 2. Transactional, Async 注解失效? 当在动态代理方法中调用当前 ...

  5. 【leetcode】1051. Height Checker

    题目如下: Students are asked to stand in non-decreasing order of heights for an annual photo. Return the ...

  6. Java浏览器弹出下载框,多个文件导出压缩包

    项目里一直有这个功能,也一直没怎么注意,今天研究了一下 依据逻辑往下走: 首先是要下载的ajax的Java方法,只有返回值需要设定一下,其他的不用管: Map<String, Object> ...

  7. MyCat的启动

    启动MyCat: ./mycat start 查看启动状态: ./mycat status 停止: ./mycat stop 重启: ./mycat restart 

  8. C# 获取路径中,文件名、目录、扩展名等

    string path = "C:\\dir1\\dir2\\foo.txt"; string str = "GetFullPath:" + Path.GetF ...

  9. html、css、js分工,内核,html头,html表单

    html:内容css:样式js:交互 内核 浏览器控制台输入navigator.userAgent,回车显示出内核"Mozilla/5.0 (Windows NT 6.1; WOW64) A ...

  10. python发送消息到ipmsg

    from socket import * #利用socket模块生成套接字s = socket(AF_INET,SOCK_DGRAM) #定义一个元组,包含ip地址,和端口号,ip地址必须为字符串,端 ...