[Bzoj2243][SDOI2011]染色(线段树&&树剖||LCT)
题目链接: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)的更多相关文章
- bzoj2243: [SDOI2011]染色--线段树+树链剖分
此题代码量较大..但是打起来很爽 原本不用lca做一直wa不知道为什么.. 后来改lca重打了一遍= =结果一遍就AC了orz 题目比较裸,也挺容易打,主要是因为思路可以比较清晰 另:加读入优化比没加 ...
- [BZOJ2243][SDOI2011]染色 解题报告|树链剖分
Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“ ...
- BZOJ2243 SDOI2011 染色 【树链剖分】
BZOJ2243 SDOI2011 染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色 ...
- bzoj2243[SDOI2011]染色 树链剖分+线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9012 Solved: 3375[Submit][Status ...
- bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 7925 Solved: 2975[Submit][Status ...
- 洛谷$P2486\ [SDOI2011]$染色 线段树+树链剖分
正解:线段树+树链剖分 解题报告: 传送门$QwQ$ 其实是道蛮板子的题,,,但因为我写得很呆然后写了贼久之后发现想法有问题要重构,就很难受,就先写个题解算了$kk$ 考虑先跑个树剖,然后按$dfn$ ...
- 【树链剖分】bzoj2243 [SDOI2011]染色
树链剖分模板题.线段树维护每个段中的颜色数.左端点颜色.右端点颜色. pushup: col[rt]=col[rt<<1]+col[rt<<1|1]-(Rcol[rt<& ...
- BZOJ2243: [SDOI2011]染色(树链剖分/LCT)
Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如 ...
- BZOJ2243[SDOI2011]染色——树链剖分+线段树
题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如“112221 ...
随机推荐
- vue.js(10)--案例--列表增加与删除
品牌管理案例 (1)bootstrip快速布局 <div class="app"> <div class="panel panel-primary&qu ...
- C++宽字符串转字符串
这文章是更改别人代码 #include <string> #include <iostream> #include <stdlib.h> #include < ...
- linux配置 sudo 授权管理
为什么使用 sudo,如果普通用户使用 su - root 切换到管理员.进行非法操作,比如 passwd root 修改 root 密码.那么系统其他用户将无法访问系统.这个普通管理员说白了,已经” ...
- 【rabbitmq】解决SimpleAmqpClient创建连接时阻塞的问题
https://blog.csdn.net/panxianzhan/article/details/50755409 https://blog.csdn.net/csm201314/article/d ...
- 一、ARM
1.1 ARM 分类 1.1.1 版本号分类 以前分类的是 ARM7,ARM9... ARM11,在 ARM11 之后,就是以 Cortex 系列分类了: Cortex-R:应用在实时系统上的系列 C ...
- vue-cli 2.0搭建vue脚手架步骤
1.安装node 检测版本node -v 2.安装webpack npm install webpack -g 检测版本 webpack -v 3.安装vue-cli npm install vue- ...
- 【leetcode】1027. Longest Arithmetic Sequence
题目如下: Given an array A of integers, return the length of the longest arithmetic subsequence in A. Re ...
- 如何判断WebBrowser浏览器网页加载完成
在工作中遇到了这样的问题,那就是要判断WebBrowser浏览器网页是否加载完成,通过搜索发现网友们解决这一问题的几种方法,但都不能解决实际问题,现在我们就来看看网友们是如何解决这一问题的. 一.通过 ...
- Arithmetic Sequence
Arithmetic Sequence Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Othe ...
- eureka注册中心wro.css wro.js 404
注册中心和配置中心放在一个module里面,如果不配置配种中心的访问前缀,会被config拦截.所以改动如下: package com.cloud.stagging.lhcloudeureka; im ...