树链剖分+区间染色

因为是一颗树不是森林,所以应该用树剖就行,但是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. 【代码笔记】Web-CSS-CSS盒子模型

    一,效果图. 二,代码. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  2. 【20190305】CSS-响应式图片:srcset+sizes,picture,svg

    响应式图片可以根据不同的设备屏幕大小从而选择加载不同的图片,从而节省带宽.实现响应式图片有三种方法:srcset+sizes属性.picture标签.svg 1. srcset+sizes srcse ...

  3. Net中获取程序集路径

      从内存中加载的程序集,无路径   IIS中路径 protected void Page_Load(object sender, EventArgs e) { Response.Write(&quo ...

  4. Belgrade Azure 2019-2-11活动感悟

    这是<国外线下技术俱乐部建设>系列文章之一.   活动网址:https://www.meetup.com/Azure-UG-Srbija/events/258673179/ 活动内容:Az ...

  5. Error occurred during initialization of VM Could not reserve enough space for 2097152KB object heap

    ionic build Android后的报错问题 ionic 升级了splashscreen和statusbar的插件后,执行ionic build android会一直报打包错误.原因是过低的An ...

  6. vue安装和使用

    首先这里记录的是基于安装node.js 的npm安装vue  如果你不是用的node与npm  那就不必往下看了 1.安装node.js这个不多说   百度有很多 2.安装webpack 全局安装we ...

  7. 记阿里云SLB后配置Nginx反向代理百度地图API的坑

    需求: 百度的原始请求:https://api.map.baidu.com/place/v2/suggestion?query=s&region=sc&city_limit=true& ...

  8. c#二进制移位运算符 "<<"及">>","&","|","^"

    移位运算符 & :按位与,其实与&&逻辑运算符有一致的地方: | :按位或,同样与||有类似的地方. ~:按位取反 ^:按位异或 <<:左移运算符 >> ...

  9. e297: write error in swap file

    磁盘空间不足: [root@ipservice fountain]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/dock ...

  10. SQL NOT NULL 约束

    SQL NOT NULL 约束 NOT NULL 约束强制列不接受 NULL 值. NOT NULL 约束强制字段始终包含值.这意味着,如果不向字段添加值,就无法插入新记录或者更新记录. 下面的 SQ ...