题目

Description

给定一棵有n个节点的无根树和m个操作,操作有2类:

1、将节点a到节点b路径上所有点都染成颜色c;

2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。

请你写一个程序依次完成这m个操作。

Sample Input

6 5

2 2 1 2 1 1

1 2

1 3

2 4

2 5

2 6

Q 3 5

C 2 1 1

Q 3 5

C 5 1 2

Q 3 5

Sample Output

3

1

2

HINT

数N<=105,操作数M<=105,所有的颜色C为整数且在[0, 10^9]之间。

分析

我实在是懒得分析了emm...这题目调了半天!!!

还是写写吧

正解: 树剖+线段树

因为要判断颜色的段数,所以想到在线段树里要维护个左右端点的颜色,并且在查询的时候要判断颜色,为了防止算重复。

线段树的操作就不写了(垃圾博主就是忘了写下传tag到儿子的tag, 他脑子让驴给踢了,不用管他)(注意,线段树的query可能要变一下),考虑查询操作:当前链与上一次的链在相交的边缘可能颜色相同,如果颜色相同答案需要减一。所以统计答案的时候要记录下上一次剖到的链所在线段树区间左端点每次与当前链所在线段树的右端点比较(想想线段树的查询in[]数组)

又由于有x和y两个位置在向上走,那么要记录ans1,ans2两个变量来存“上一次的左端点颜色”, 每次交换x,y时记得交换ans1,ans2

注意最后在同一条重链上时情况不一样,需要自己手胡一下

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 100000+99;
const int MAXM = MAXN<<1; int n, m;
int pos[MAXN];
struct node{
int deep, size, fa, son, tp, in, color;
}a[MAXN];
int _clock; struct seg{
int y, next;
}e[MAXM];
int head[MAXN], cnt;
void add_edge(int x, int y) {
e[++cnt].y = y;
e[cnt].next = head[x];
head[x] = cnt;
} void dfs1(int x, int fa) {
a[x].deep = a[fa].deep + 1;
a[x].fa = fa;
a[x].size = 1;
for(int i = head[x]; i; i = e[i].next)
if(e[i].y != fa) {
dfs1(e[i].y, x);
a[x].size += a[e[i].y].size;
a[x].son = a[a[x].son].size > a[e[i].y].size ? a[x].son : e[i].y;
}
} struct tree{
int mx, L, R, lazyset;
}tr[MAXN<<2];
void dfs2(int x, int tp) {
a[x].tp = tp;
a[x].in = ++_clock;
pos[_clock] = a[x].color;
if(a[x].son) dfs2(a[x].son, tp);
for(int i = head[x]; i; i = e[i].next)
if(e[i].y != a[x].fa && e[i].y != a[x].son) {
dfs2(e[i].y, e[i].y);
}
} void pushup(int o) {
tr[o].mx = tr[o<<1].mx + tr[o<<1|1].mx;
if(tr[o<<1].R == tr[o<<1|1].L) tr[o].mx--;
tr[o].L = tr[o<<1].L;
tr[o].R = tr[o<<1|1].R;//别写漏了
}
void build(int o, int l, int r) {
tr[o].lazyset = 0;
if(l == r) {
tr[o].L = tr[o].R = pos[l];
tr[o].mx = 1;
return ;
}
int mid = (l+r)>>1;
build(o<<1, l, mid);
build(o<<1|1, mid+1, r);
pushup(o);
} void pushdown(int o) {
if(tr[o].lazyset == 0) return ;
tr[o<<1].L = tr[o<<1].R = tr[o].lazyset ;
tr[o<<1|1].L = tr[o<<1|1].R = tr[o].lazyset ;
tr[o<<1].mx = tr[o<<1|1].mx = 1;
tr[o<<1].lazyset = tr[o<<1|1].lazyset = tr[o].lazyset ;
tr[o].lazyset = 0;
}
void optset(int o, int l, int r, int ql, int qr, int k) {
if(ql <= l && r <= qr) {
tr[o].L = tr[o].R = k;
tr[o].mx = 1;
tr[o].lazyset = k;
return ;
}
pushdown(o);
int mid = (l+r)>>1;
if(ql <= mid) optset(o<<1, l, mid, ql, qr, k);
if(mid < qr) optset(o<<1|1, mid+1, r, ql, qr, k);
pushup(o);
} int Lcolor, Rcolor;
int query(int o, int l, int r, int ql, int qr) {
if(l == ql) Lcolor = tr[o].L;
if(r == qr) Rcolor = tr[o].R;
if(ql <= l && r <= qr) {
return tr[o].mx ;
}
int mid = (l+r)>>1, ans = 0;
pushdown(o);
//需要求出Lcolor和Rcolor,所以要像下面这样写...?
if(qr <= mid) {
return query(o<<1, l, mid, ql, qr);
} else if(mid < ql) {
return query(o<<1|1, mid+1, r, ql, qr);
} else {
ans += query(o<<1, l, mid, ql, qr);
ans += query(o<<1|1, mid+1, r,ql, qr);
if(tr[o<<1].R == tr[o<<1|1].L) ans--;
return ans;
}
//线段树查询的时候也要考虑
} void ttt_update(int x, int y, int k) {
while(a[x].tp != a[y].tp) {
if(a[a[x].tp].deep < a[a[y].tp].deep) swap(x,y);
optset(1, 1, n, a[a[x].tp].in, a[x].in, k);
x = a[a[x].tp].fa;
}
if(a[x].deep > a[y].deep) swap(x,y);
optset(1, 1, n, a[x].in, a[y].in, k);
} int ttt_query(int x, int y) {
int ans = 0, ans1 = -1, ans2 = -1;
//ans1,ans2分别记录x,y 上一条被剖的链所在线段树的区间的左端点
//每次与当前链所在线段树的右端点比较(想想线段树的查询和in[]数组)
while(a[x].tp != a[y].tp) {
if(a[a[x].tp].deep < a[a[y].tp].deep) {
swap(x, y);
swap(ans1, ans2);
}
ans += query(1, 1, n, a[a[x].tp].in, a[x].in);
if(ans1 == Rcolor) {
ans--;
}
ans1 = Lcolor;
x = a[a[x].tp].fa;
}
if(a[x].deep > a[y].deep) {
swap(x, y);
swap(ans1, ans2);
}
// if(a[x].deep < a[y].deep)
// swap(x,y),swap(ans1,ans2);
ans += query(1, 1, n, a[x].in, a[y].in);
if(ans1 == Lcolor) ans--;
if(ans2 == Rcolor) ans--;
return ans;
} int main() {
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++) scanf("%d",&a[i].color);
int x,y;
for(int i = 1; i < n; i++) {
scanf("%d%d",&x, &y);
add_edge(x,y);
add_edge(y,x);
}
dfs1(1, 0);
dfs2(1, 1);
build(1, 1, n);
char cmd;
int k;
for(int i = 1; i <= m; i++) {
cin>>cmd;
if(cmd == 'C') {
scanf("%d%d%d",&x,&y,&k);
ttt_update(x, y, k);
} else {
scanf("%d%d",&x,&y);
printf("%d\n",ttt_query(x,y));
}
}
}

luoguP2486 [SDOI2011]染色的更多相关文章

  1. [luoguP2486] [SDOI2011]染色(树链剖分)

    传送门 就是个模板啦 记录每一个点的左端点颜色和右端点颜色和当前端点颜色段数. 合并时如果左孩子右端点和右孩子左端点不同就 ans-- 在重链上跳的时候别忘记统计一下 ——代码 #include &l ...

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

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

  3. bzoj-2243 2243: [SDOI2011]染色(树链剖分)

    题目链接: 2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6267  Solved: 2291 Descript ...

  4. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

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

  5. bzoj2243:[SDOI2011]染色

    链剖就可以了.一开始的想法错了.但也非常接近了.妈呀调的要死...然后把字体再缩小一号查错起来比较容易QAQ. #include<cstdio> #include<cstring&g ...

  6. bzoj 2243 [SDOI2011]染色(树链剖分,线段树)

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

  7. Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树

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

  8. 2243: [SDOI2011]染色

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

  9. bzoj 2243 [SDOI2011]染色(树链剖分+线段树合并)

    [bzoj2243][SDOI2011]染色 2017年10月20日 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询 ...

随机推荐

  1. bay——Oracle RAC环境下ASM磁盘组扩容.docx

    https://www.cnblogs.com/polestar/p/10115263.html Oracle RAC环境下ASM磁盘组扩容 生产环境注意调整以下参数: +++++++++++++++ ...

  2. 电池的QPNP模式

    名词解释: CV:Constant Voltage恒压 SMMB charger:Switch-ModeBattery Charger and Boost peripheral开关模式电池充电器和升压 ...

  3. iotop使用方法

    iotop 是一个用来监视磁盘 I/O 使用状况的 top 类工具.iotop 具有与 top 相似的 UI,其中包括 PID.用户.I/O.进程等相关信息.   安装 yum install iot ...

  4. 2019年最新50道java基础部分面试题(二)

    前11题请看上一篇文章 12.静态变量和实例变量的区别?  在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加. 在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对 ...

  5. maven clean插件使用进阶

    maven clean插件使用进阶 参考 Maven clean 插件 Maven删除外部文件 查看命令帮助 mvn clean:help mvn clean:help -Ddetail=true - ...

  6. BZOJ2339/LG3214 「HNOI2011」 卡农 组合数学

    问题描述 BZOJ2339 本题的一些心得 对于这种无序集合计数类问题,可以通过对方案数除以某个数的阶乘,使得无序化变为有序化. 设计DP方程时候,应该先有序的列出状态转移方程每一项的来源,并一项项推 ...

  7. Go 变量(var) & 常量(const)

    变量 声明变量格式: var var_name var_type 变量在声明时会自动初始化: 数字: 0 string: "" bool: false 引用类型: nil 结构体: ...

  8. 前端 用http-server启动本地服务器

    附:http-server详细介绍,包括参数等:  https://www.npmjs.com/package/http-server 开始: 准备node.js环境: 在我的博文“  Vue.js学 ...

  9. 跳出"低水平勤奋陷阱"

    "低水平勤奋陷阱":摘记更多的知识 读书是获得知识的最基本,最重要的方式,但读书需要方法 所谓"低水平勤奋陷阱",就是花费了大量的时间和精力,但得到的结果却微乎 ...

  10. Selenium+java - 单选框及复选框处理

    一.什么是单选框.复选框? 二.被测页面html源代码 CheckBoxRadioDemo.html <!DOCTYPE html> <html lang="en" ...