树链剖分+区间染色

因为是一颗树不是森林,所以应该用树剖就行,但是LCT好像也能写。。

直接用线段树维护树上的节点,注意pushdown还有询问的时候要考虑区间相交的地方,也就是左孩子右边和有孩子的左边,如果两个颜色相同就-1

树上询问的时候也是一样,跨越轻链的时候也要看一下相接的地方颜色是不是一样。。w

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define full(a, b) memset(a, b, sizeof a)
using namespace std;
typedef long long ll;
inline int lowbit(int x){ return x & (-x); }
inline int read(){
int X = 0, w = 0; char ch = 0;
while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
return w ? -X : X;
}
inline int gcd(int a, int b){ return a % b ? gcd(b, a % b) : b; }
inline int lcm(int a, int b){ return a / gcd(a, b) * b; }
template<typename T>
inline T max(T x, T y, T z){ return max(max(x, y), z); }
template<typename T>
inline T min(T x, T y, T z){ return min(min(x, y), z); }
template<typename A, typename B, typename C>
inline A fpow(A x, B p, C lyd){
A ans = 1;
for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;
return ans;
} const int N = 100005;
int n, m, cnt, dfn, head[N], size[N], depth[N], p[N], son[N], top[N], val[N], w[N], id[N];
int tree[N<<2], lc[N<<2], rc[N<<2], c[N<<2];
struct Edge { int v, next; } edge[N<<1]; void addEdge(int a, int b){
edge[cnt].v = b, edge[cnt].next = head[a], head[a] = cnt ++;
} void dfs1(int s, int fa){
depth[s] = depth[fa] + 1;
p[s] = fa;
size[s] = 1;
int child = -1;
for(int i = head[s]; i != -1; i = edge[i].next){
int u = edge[i].v;
if(u == fa) continue;
dfs1(u, s);
size[s] += size[u];
if(size[u] > child) child = size[u], son[s] = u;
}
} void dfs2(int s, int tp){
id[s] = ++dfn;
w[id[s]] = val[s];
top[s] = tp;
if(son[s] != -1) dfs2(son[s], tp);
for(int i = head[s]; i != -1; i = edge[i].next){
int u = edge[i].v;
if(u == p[s] || u == son[s]) continue;
dfs2(u, u);
}
} void push_up(int rt){
int l = rt << 1, r = rt << 1 | 1;
tree[rt] = tree[l] + tree[r];
lc[rt] = lc[l], rc[rt] = rc[r];
if(rc[l] == lc[r]) tree[rt] --;
} void push_down(int rt){
//printf("c[%d] = %d\n", rt, c[rt]);
if(c[rt] != -1){
int ls = rt << 1, rs = rt << 1 | 1;
c[ls] = c[rs] = c[rt];
tree[ls] = tree[rs] = 1;
lc[ls] = rc[ls] = lc[rs] = rc[rs] = c[rt];
c[rt] = -1;
}
} void buildTree(int rt, int l, int r){
if(l == r){
tree[rt] = 1, c[rt] = -1, lc[rt] = rc[rt] = w[l];
return;
}
int mid = (l + r) >> 1;
buildTree(rt << 1, l, mid);
buildTree(rt << 1 | 1, mid + 1, r);
push_up(rt);
} void modify(int rt, int l, int r, int ml ,int mr, int tot){
if(l == ml && r == mr){
c[rt] = tot, tree[rt] = 1, lc[rt] = rc[rt] = tot;
return;
}
push_down(rt);
int mid = (l + r) >> 1;
if(ml > mid) modify(rt << 1 | 1, mid + 1, r, ml, mr, tot);
else if(mr <= mid) modify(rt << 1, l, mid, ml, mr, tot);
else modify(rt << 1, l, mid, ml, mid, tot), modify(rt << 1 | 1, mid + 1, r, mid + 1, mr, tot);
push_up(rt);
} int query(int rt, int l, int r, int ql, int qr){
if(l == ql && r == qr){
return tree[rt];
}
push_down(rt);
int mid = (l + r) >> 1;
if(ql > mid) return query(rt << 1 | 1, mid + 1, r, ql, qr);
else if(qr <= mid) return query(rt << 1, l, mid, ql, qr);
else{
int ls = query(rt << 1, l, mid, ql, mid);
int rs = query(rt << 1 | 1, mid + 1, r, mid + 1, qr);
return rc[rt << 1] == lc[rt << 1 | 1] ? ls + rs - 1 : ls + rs;
}
} int color(int rt, int l, int r, int index){
if(l == r) return lc[rt];
push_down(rt);
int mid = (l + r) >> 1;
if(index > mid) return color(rt << 1 | 1, mid + 1, r, index);
return color(rt << 1, l, mid, index);
} void treeModify(int x, int y, int tot){
while(top[x] != top[y]){
if(depth[top[x]] < depth[top[y]]) swap(x, y);
modify(1, 1, n, id[top[x]], id[x], tot);
x = p[top[x]];
}
if(depth[x] > depth[y]) swap(x, y);
modify(1, 1, n, id[x], id[y], tot);
} int treeQuery(int x, int y){
int ret = 0;
while(top[x] != top[y]){
if(depth[top[x]] < depth[top[y]]) swap(x, y);
ret += query(1, 1, n, id[top[x]], id[x]);
if(color(1, 1, n, id[top[x]]) == color(1, 1, n, id[p[top[x]]])) ret --;
x = p[top[x]];
}
if(depth[x] > depth[y]) swap(x, y);
ret += query(1, 1, n, id[x], id[y]);
return ret;
} int main(){ full(head, -1), full(son, -1), full(c, -1);
n = read(), m = read();
for(int i = 1; i <= n; i ++) val[i] = read();
for(int i = 0; i < n - 1; i ++){
int u = read(), v = read();
addEdge(u, v), addEdge(v, u);
}
dfs1(1, 0), dfs2(1, 1);
buildTree(1, 1, n);
while(m --){
char opt[10]; scanf("%s", opt);
int a = read(), b = read();
if(opt[0] == 'C'){
int c = read();
treeModify(a, b, c);
}
else if(opt[0] == 'Q'){
printf("%d\n", treeQuery(a, b));
}
}
return 0;
}

于是我换了个LCT的做法

交换区间的时候注意把lc和rc也换下,其他的没啥区别。

但是我在link的时候加了个pushup,然后莫名WA。。难道不能加的吗qwq,就算左右子树为0,pushup也不会改变什么啊。。。

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define full(a, b) memset(a, b, sizeof a)
using namespace std;
typedef long long ll;
inline int lowbit(int x){ return x & (-x); }
inline int read(){
int X = 0, w = 0; char ch = 0;
while(!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }
while(isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
return w ? -X : X;
}
inline int gcd(int a, int b){ return a % b ? gcd(b, a % b) : b; }
inline int lcm(int a, int b){ return a / gcd(a, b) * b; }
template<typename T>
inline T max(T x, T y, T z){ return max(max(x, y), z); }
template<typename T>
inline T min(T x, T y, T z){ return min(min(x, y), z); }
template<typename A, typename B, typename C>
inline A fpow(A x, B p, C lyd){
A ans = 1;
for(; p; p >>= 1, x = 1LL * x * x % lyd)if(p & 1)ans = 1LL * x * ans % lyd;
return ans;
}
const int N = 100005;
int n, m, tot, ch[N][2], c[N], lc[N], rc[N], val[N], rev[N], sum[N], fa[N], st[N]; void newNode(int v){
++tot, c[tot] = -1, lc[tot] = rc[tot] = val[tot] = v;
sum[tot] = 1, rev[tot] = ch[tot][0] = ch[tot][1] = fa[tot] = 0;
} void reverse(int x){
rev[x] ^= 1;
swap(ch[x][0], ch[x][1]);
swap(lc[x], rc[x]);
} void pushtag(int x, int e){
val[x] = lc[x] = rc[x] = e;
sum[x] = 1, c[x] = e;
} void push_up(int x){
int l = ch[x][0], r = ch[x][1];
lc[x] = l ? lc[l] : val[x];
rc[x] = r ? rc[r] : val[x];
if(l && r) sum[x] = sum[l] + sum[r] + 1 - (rc[l] == val[x]) - (lc[r] == val[x]);
else if(l) sum[x] = sum[l] + 1 - (rc[l] == val[x]);
else if(r) sum[x] = sum[r] + 1 - (lc[r] == val[x]);
else sum[x] = 1;
} void push_down(int x){
if(rev[x]){
int l = ch[x][0], r = ch[x][1];
if(l) reverse(l);
if(r) reverse(r);
rev[x] ^= 1;
}
if(c[x] != -1){
int l = ch[x][0], r = ch[x][1];
if(l) pushtag(l, c[x]);
if(r) pushtag(r, c[x]);
c[x] = -1;
}
} bool isRoot(int x){
return (ch[fa[x]][0] != x && ch[fa[x]][1] != x);
} void rotate(int x){
int y = fa[x], z = fa[y], p = (ch[y][1] == x) ^ 1;
push_down(y), push_down(x);
ch[y][p^1] = ch[x][p], fa[ch[x][p]] = y;
if(!isRoot(y)) ch[z][ch[z][1] == y] = x;
fa[x] = z, fa[y] = x, ch[x][p] = y;
push_up(y), push_up(x);
} void splay(int x){
int pos = 0; st[++pos] = x;
for(int i = x; !isRoot(i); i = fa[i]) st[++pos] = fa[i];
while(pos) push_down(st[pos--]);
while(!isRoot(x)){
int y = fa[x], z = fa[y];
if(!isRoot(y)){
(ch[y][0] == x) ^ (ch[z][0] == y) ? rotate(x) : rotate(y);
}
rotate(x);
}
push_up(x);
} void access(int x){
for(int p = 0; x; p = x, x = fa[x])
splay(x), ch[x][1] = p, push_up(x);
} void makeRoot(int x){
access(x), splay(x), reverse(x);
} void link(int x, int y){
makeRoot(x), fa[x] = y;//push_up(y);
} void split(int x, int y){
makeRoot(x), access(y), splay(y);
} int main(){ full(c, -1);
n = read(), m = read();
for(int i = 1; i <= n; i ++){
int v = read();
newNode(v);
}
for(int i = 0; i < n - 1; i ++){
int u = read(), v = read();
link(u, v);
}
while(m --){
char opt[10]; scanf("%s", opt);
int a = read(), b = read();
if(opt[0] == 'C'){
int i = read();
split(a, b);
pushtag(b, i);
}
else if(opt[0] == 'Q'){
split(a, b);
printf("%d\n", sum[b]);
}
}
return 0;
}

BZOJ 2243 染色的更多相关文章

  1. BZOJ 2243 染色 | 树链剖分模板题进阶版

    BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...

  2. BZOJ 2243 染色(树链剖分好题)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 7971  Solved: 2990 [Submit][Stat ...

  3. BZOJ 2243 染色 (线段树+树链剖分)

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

  4. BZOJ - 2243 染色 (树链剖分+线段树+区间合并)

    题目链接 线段树维护区间连续段个数即可.设lc为区间左端点颜色,rc为区间右端点颜色,则合并两区间的时候,如果左区间右端点和右区间左端点颜色相同,则连续段个数-1. 在树链上的区间合并可以定义一个结构 ...

  5. BZOJ 2243 染色 树链剖分

    题意: 给出一棵树,每个顶点上有个颜色\(c_i\). 有两种操作: C a b c 将\(a \to b\)的路径所有顶点上的颜色变为c Q a b 查询\(a \to b\)的路径上的颜色段数,连 ...

  6. BZOJ - 2243 染色 (LCT链修改+链查询)

    同样是可以用LCT解决的树剖问题之一. 注意反转的时候要考虑对左右端点颜色的影响,而且要先反转再打标记(这点不知道为啥) #include<bits/stdc++.h> using nam ...

  7. [BZOJ 2243] [SDOI 2011] 染色 【树链剖分】

    题目链接:BZOJ - 2243 题目分析 树链剖分...写了200+行...Debug了整整一天+... 静态读代码读了 5 遍 ,没发现错误,自己做小数据也过了. 提交之后全 WA . ————— ...

  8. hysbz 2243 染色(树链剖分)

    题目链接:hysbz 2243 染色 题目大意:略. 解题思路:树链剖分+线段树的区间合并,可是区间合并比較简单,节点仅仅要记录左右端点的颜色就可以. #include <cstdio> ...

  9. BZOJ 2243: [SDOI2011]染色 [树链剖分]

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

随机推荐

  1. 从.Net到Java学习第一篇——开篇

    以前我常说,公司用什么技术我就学什么.可是对于java,我曾经一度以为“学java是不可能的,这辈子不可能学java的.”结果,一遇到公司转java,我就不得不跑路了,于是乎,回头一看N家公司交过社保 ...

  2. 【阿里云】在 Windows Server 2016 下使用 FileZilla Server 安装搭建 FTP 服务

     Windows Server 2016 下使用 FileZilla Server 安装搭建 FTP 服务 一.安装 Filezilla Server 下载最新版本的 Filezilla Server ...

  3. Android学习笔记之SoftReference软引用,弱引用WeakReference

    SoftReference可以用于bitmap缓存 WeakReference 可以用于handler 非静态内部类和匿名内部类容易造成内存泄漏 private Handler mRemoteHand ...

  4. Flask框架搭建REST-API服务

    一.目的 为了能够将测试工具部署成RESTful-API服务,这样就能通过接口的方式提供统一测试工具服务,使用人员就不用构建application而产生的各种环境问题.使用问题. 适合人群:Pytho ...

  5. gitbook 入门教程之插件介绍

    插件是 gitbook 的扩展功能,很多炫酷有用的功能都是通过插件完成的,其中插件有官方插件和第三方插件之分. 推荐官方插件市场 https://plugins.gitbook.com/ 寻找或下载相 ...

  6. php去掉字符串的最后一个字符

    php去掉字符串的最后一个字符 //例如 $str = "12,34,56,"; $newstr = substr($str,0,strlen($str)-1); //从第一位开始 ...

  7. 电脑出现问题如何修复Windows 10

    也许Windows 10无法启动.或者它可能会靴子,但会崩溃很多.在任何一种情况下,您都需要在使用PC之前解决问题.以下是修复Windows 10的几种方法. 方法1:使用Windows启动修复 如果 ...

  8. 使用Visual Studio Code进行ABAP开发

    长期以来,我们都使用SAP GUI进行ABAP编码工作,事务代码SE38甚至成了ABAP的代名词. SAP GUI的代码编辑能力和一些专业的IDE比较起来难免相形见绌,为了给开发者们更好的体验,SAP ...

  9. parquet文件 读取 原理

    学习一下parquet存储结构 原理 以及使用

  10. yum makecache

    $ yum makecache 就是把服务器的包信息下载到本地电脑缓存起来,makecache建立一个缓存,以后用install时就在缓存中搜索,提高了速度.配合yum -C search xxx使用 ...