[SDOI2011]染色

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 6870  Solved: 2546
[Submit][Status][Discuss]

Description

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

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

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

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

Input

第一行包含2个整数n和m,分别表示节点数和操作数;

第二行包含n个正整数表示n个节点的初始颜色

下面行每行包含两个整数x和y,表示xy之间有一条无向边。

下面行每行描述一个操作:

“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;

“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

Output

对于每个询问操作,输出一行答案。

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<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。

【分析】此题的难点在于处理颜色块的个数。考虑到若两个区间合并,颜色块的个数取决于两边的个数和合并处的两个接口处颜色是否相等,相等则-1.所以对于每个线段树结点(代表区间)维护三个数组--sum[]:此区间的颜色块数;s[]:此区间左端的颜色;t[]:此区间右端的颜色。所以区间合并时,若左儿子的右端点与右儿子的左端点相等,则

sum[rt]=sum[rt*2]+sum[rt*2+1]-1,否则不-1.区间修改采用lazy[]标记。(敲了一下午,调了一晚上,最后发现是个很SB的错误,日。。。)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <time.h>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define met(a,b) memset(a,b,sizeof a)
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int N=2e5+;
const int M=N*N+;
int dep[N],siz[N],fa[N],id[N],son[N],val[N],top[N],c[N];
int num,m,n,q,tot=;
int sum[N*];
int lazy[N*],head[N],s[N*],t[N*];
struct tree {
int to,next;
} edg[N*];
void add(int u,int v) {
edg[tot].to=v;
edg[tot].next=head[u];
head[u]=tot++;
}
void dfs1(int u, int f, int d) {
dep[u] = d;
siz[u] = ;
son[u] = ;
fa[u] = f;
for (int i = head[u]; i != -; i=edg[i].next) {
int ff = edg[i].to;
if (ff == f) continue;
dfs1(ff, u, d + );
siz[u] += siz[ff];
if (siz[son[u]] < siz[ff])
son[u] = ff;
}
}
void dfs2(int u, int tp) {
top[u] = tp;
id[u] = ++num;
if (son[u]) dfs2(son[u], tp);
for (int i = head[u]; i != -; i=edg[i].next) {
int ff = edg[i].to;
if (ff == fa[u] || ff == son[u]) continue;
dfs2(ff, ff);
}
}
void Push_up(int rt) {
if(t[rt*]==s[rt*+])sum[rt]=sum[rt*]+sum[rt*+]-;
else sum[rt]=sum[rt*]+sum[rt*+];
s[rt]=s[rt*];
t[rt]=t[*rt+];
}
void Push_down(int rt) {
if(lazy[rt]) {
s[*rt]=s[*rt+]=t[*rt]=t[*rt+]=lazy[rt];
lazy[*rt]=lazy[rt];
lazy[*rt+]=lazy[rt];
sum[*rt]=sum[*rt+]=;
lazy[rt]=;
}
}
void Build(int l,int r,int rt) {
if(l==r) {
lazy[rt]=s[rt]=t[rt]=val[l];
sum[rt]=;
return;
}
Push_down(rt);
int m=(l+r)>>;
Build(lson);
Build(rson);
Push_up(rt);
}
void Update(int L,int R,int l,int r,int rt,int add) {
if(l>=L&&r<=R) {
lazy[rt]=add;
s[rt]=t[rt]=add;
sum[rt]=;
return;
}
Push_down(rt);
int m=(r+l)>>;
if(L<=m)Update(L,R,lson,add);
if(R>m) Update(L,R,rson,add);
Push_up(rt);
}
int Query(int L,int R,int l,int r,int rt) {
if(L<=l&&r<=R)return sum[rt];
Push_down(rt);
int m=(l+r)>>,ans=;
if(L<=m)ans+=Query(L,R,lson);
if(R>m)ans+=Query(L,R,rson);
if(L<=m && R>m && s[rt*+]==t[rt*])ans--;
return ans;
}
void solve(int u,int v,int add) {
int tp1 = top[u], tp2 = top[v];
while (tp1 != tp2) {
if (dep[tp1] < dep[tp2]) {
swap(tp1, tp2);
swap(u, v);
}
Update(id[tp1],id[u],,n,,add);
u = fa[tp1];
tp1 = top[u];
}
if (dep[u] > dep[v]) swap(u, v);
Update(id[u],id[v],,n,,add);
return;
}
int _find(int u,int l,int r,int rt){
if(l==r)return s[rt];
Push_down(rt);
int m=(l+r)/;
if(u<=m)return _find(u,l,m,rt*);
else return _find(u,m+,r,rt*+);
}
int Answer(int u,int v) {
int tp1 = top[u], tp2 = top[v];
int ans=;
while (tp1 != tp2) {
if (dep[tp1] < dep[tp2]) {
swap(tp1, tp2);
swap(u, v);
}
ans +=Query(id[tp1], id[u],,n,);
u = fa[tp1];
if(_find(id[tp1],,n,)==_find(id[u],,n,))ans--;
tp1 = top[u];
}
if (dep[u] > dep[v]) swap(u, v);
ans += Query(id[u], id[v],,n,);
return ans;
}
int main() {
scanf("%d%d",&n,&m);
met(head,-);
int u,v,w;
for(int i=; i<=n; i++) {
scanf("%d",&c[i]);
}
for(int i=; i<n; i++) {
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
num = ;
dfs1(,,);
dfs2(,);
for (int i = ; i <= n; i++) {
val[id[i]]=c[i];
}
Build(,num,);
char str[];
while(m--) {
scanf("%s",str);
if(str[]=='C') {
scanf("%d%d%d",&u,&v,&w);
solve(u,v,w);
} else {
scanf("%d%d",&u,&v);
printf("%d\n",Answer(u,v));
}
}
return ;
}

BZOJ 2243 [SDOI2011]染色 (树链剖分)(线段树区间修改)的更多相关文章

  1. 2243: [SDOI2011]染色 树链剖分+线段树染色

    给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如“112221”由3段组 ...

  2. bzoj2243[SDOI2011]染色 树链剖分+线段树

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

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

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

  4. B20J_2243_[SDOI2011]染色_树链剖分+线段树

    B20J_2243_[SDOI2011]染色_树链剖分+线段树 一下午净调这题了,争取晚上多做几道. 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成 ...

  5. BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)

    题目链接 BZOJ2243 树链剖分 $+$ 线段树 线段树每个节点维护$lc$, $rc$, $s$ $lc$代表该区间的最左端的颜色,$rc$代表该区间的最右端的颜色 $s$代表该区间的所有连续颜 ...

  6. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  7. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  8. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  9. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  10. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

随机推荐

  1. Python import与from import使用

    Python程序可以调用一组基本的函数(即内建函数),比如print().input()和len()等函数.Python本身也内置一组模块(即标准库).每个模块都是一个Python程序,且包含了一组相 ...

  2. APP测试工程师面试题:之一

    第六题主要流程:编写计划 → 测试用例 → 评审用例 → 执行用例 → 写BUG →测修复情况 → 上线

  3. cloud-init代码调试方法

    新做的centos7.4镜像的cloud-init安装好之后,修改密码失败,但是同样的配置文件在7.2上的是正常的,对比了一下版本,centos7.4上的是0.7.9,7.2上的是0.7.5,经过调试 ...

  4. 【Python】print 方法的参数

    当在IDEL或者命令行中执行 help(print) 命令时,就可以看到 print 方法的详细说明: print(value, ..., sep=' ', end='\n', file=sys.st ...

  5. Python——开篇之词

    我也断断续续的用Python挺长时间了.但是一直都没有系统的学习过Python.很多东西都是现用现学.这样感觉对Python的理解太浅,完完全全就是搬砖的. 因此,我专门找了一个比较完整的老男孩的Py ...

  6. HDU 4101 Ali and Baba (思路好题)

    与其说这是个博弈,倒不如说是个搜索.这题思路不错,感觉很难把情况考虑周全. 在地图外围填充一圈0,两次BFS,第一次从-1点出发,把从-1到达的0点以及包围0的那一圈石头标记出来.如下图: 1 1 1 ...

  7. maven学习(十七)——在eclipse中导入外部maven项目

    外部maven项目,导入Eclipse中进行开发 操作步骤如下所示:

  8. ocrosoft Contest1316 - 信奥编程之路~~~~~第三关 问题 J: 外币兑换

    http://acm.ocrosoft.com/problem.php?cid=1316&pid=9 题目描述 小明刚从美国回来,发现手上还有一些未用完的美金,于是想去银行兑换成人民币.可是听 ...

  9. [SQL Server]关于标识列,标识从1开始计数的的方法

    DBCC CHECKIDENT ('表名',  RESEED, 0) //从30开始 DBCC  CHECKIDENT  (jobs,  RESEED,  30)

  10. python 读取数据库时,datetime类型无法被json序列化--解决方案

    新增针对datetime的jsonencode: # -*- coding: utf-8 -*- import json from datetime import date, datetime cla ...