luoguP2486 [SDOI2011]染色
题目
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]染色的更多相关文章
- [luoguP2486] [SDOI2011]染色(树链剖分)
传送门 就是个模板啦 记录每一个点的左端点颜色和右端点颜色和当前端点颜色段数. 合并时如果左孩子右端点和右孩子左端点不同就 ans-- 在重链上跳的时候别忘记统计一下 ——代码 #include &l ...
- BZOJ 2243: [SDOI2011]染色 [树链剖分]
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6651 Solved: 2432[Submit][Status ...
- bzoj-2243 2243: [SDOI2011]染色(树链剖分)
题目链接: 2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6267 Solved: 2291 Descript ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- bzoj2243:[SDOI2011]染色
链剖就可以了.一开始的想法错了.但也非常接近了.妈呀调的要死...然后把字体再缩小一号查错起来比较容易QAQ. #include<cstdio> #include<cstring&g ...
- bzoj 2243 [SDOI2011]染色(树链剖分,线段树)
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4637 Solved: 1726[Submit][Status ...
- Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5020 Solved: 1872[Submit][Status ...
- 2243: [SDOI2011]染色
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 3113 Solved: 1204[Submit][Status ...
- bzoj 2243 [SDOI2011]染色(树链剖分+线段树合并)
[bzoj2243][SDOI2011]染色 2017年10月20日 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询 ...
随机推荐
- java直接存取MS Access的mdb数据库文件
jdbc 访问 access 的 mdb 数据库文件,使用一个叫ucanaccess的开发包实现这个功能. "Supported Access formats: 2000,2002/2003 ...
- 3. java 方法入门
一.方法定义 1. 定义格式 public static void 方法名称(){ 方法体 } 1. 方法名称:命名和变量一致,小驼峰式 2. 方法体:大括号中可以包含任意条语句 注意事项: 1. 方 ...
- vscode笔记
一.修改操作栏字体 https://www.cnblogs.com/liuyangfirst/p/9759966.html 1.代码改写,进入默认安装的如下路径,搜索workbench 2.用Vs c ...
- MySQL select from where multiple conditions
Maybe one of the most used MySQL commands is SELECT, that is the way to stract the information from ...
- EF Core 3.0 Preview 9 的2个小坑
之前我们的数据库服务器使用的是 SQL Server 2008 R2 ,由于从 EF Core 3.0 Preview 6 开始不支持 UseRowNumberForPaging ,只能停留在 EF ...
- vscode源码分析【一】从源码运行vscode
安装git,nodejs和yarn 安装Python27,3.x版本的不行,确保它在你的环境变量里: 安装gulp npm install --global gulp-cli 安装windows bu ...
- [03-2]VS2017 创建 ASP.NET Core Web 程序
VS2017 创建 ASP.NET Core Web 程序 本文作者:梁桐铭- 微软最有价值专家(Microsoft MVP) 文章会随着版本进行更新,关注我获取最新版本 本文出自<从零开始学 ...
- 【学习笔记】动态规划—各种 DP 优化
[学习笔记]动态规划-各种 DP 优化 [大前言] 个人认为贪心,\(dp\) 是最难的,每次遇到题完全不知道该怎么办,看了题解后又瞬间恍然大悟(TAT).这篇文章也是花了我差不多一个月时间才全部完成 ...
- iota: Golang 中优雅的常量
阅读约 11 分钟 注:该文作者是 Katrina Owen,原文地址是 iota: Elegant Constants in Golang 有些概念有名字,并且有时候我们关注这些名字,甚至(特别)是 ...
- Python里三个最高逼格的调试神器
调试是开发过程中不可避免的一个环节,在Python中我们使用print.logging.assert等方法进行调试既简单又实用,但毕竟有其局限性.今天这篇文章为大家带来三个工具,其中有Python的内 ...