题目

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. Android Recovery升级原理

    摘要 Recovery模式指的是一种可以对安卓机内部的数据或系统进行修改的模式(类似于windows PE或DOS).也可以称之为安卓的恢复模式,在这个所谓的恢复模式下,我们可以刷入新的安卓系统,或者 ...

  2. Python语法速查: 2. 列表、元组、字典、集合操作

    返回目录 (1)通用序列操作 “序列”表示索引为非负整数的有序对象集合,列表.元组.字符串都属于序列.区别在于:列表是可变的,而元组和字符串是不可变的.序列的通用操作他们都可以用. 操作或方法 简述 ...

  3. mysql五大引擎的区别和优劣之分

    数据库引擎介绍 MySQL数据库引擎取决于MySQL在安装的时候是如何被编译的.要添加一个新的引擎,就必须重新编译MYSQL.在缺省情况下,MYSQL支持三个引擎:ISAM.MYISAM和HEAP.另 ...

  4. PHP的stdClass

    概述 以下是百度百科对php中的 stdClass的描述: stdClass在PHP5才开始被流行.而stdClass也是zend的一个保留类.stdClass类是PHP的一个内部保留类,初始时没有成 ...

  5. 201871010113-刘兴瑞《面向对象程序设计(java)》第一周学习总结

    正文开头: 项目 内容 这个作业属于哪个课程 <任课教师博客主页链接>    https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 <作业链接 ...

  6. oracle xmltype + blob + clob

    oracle varchar2最大存储长度为4000,所以当字段长度超限时可尝试存储为blob或xmltype格式 xmltype --1.创建xml表 Create TABLE testxml( i ...

  7. 使用docker运行springboot项目

    本文主要讲的是使用docker运行springboot项目 获取一个springboot项目 这里我没有重新构建,用的之前写的一个项目,直接从github上下载下来,地址:https://github ...

  8. Educational Codeforces Round 76 (Rated for Div. 2) A. Two Rival Students 水题

    A. Two Rival Students There are

  9. python进阶之内存模型

    每一个编程语言的背后都有自己独特的内存模型支持,比如最经典的C语言,一个int类型占8字节.那么在python中不区分数据类型,定义一个变量其在内存在占用多少字节呢?python中数据的运算其内存是如 ...

  10. python学习第一天第二天总结

    变量赋值 1, 变量由字⺟, 数字,下划线搭配组合⽽成 2, 不可以⽤数字开头,更不能是全数字 3,不能是pythond的关键字, 这些符号和字⺟已经被python占⽤, 不可以更改 4,不要⽤中⽂ ...