[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全栈工程师(装饰器、模块)

    ParisGabriel                每天坚持手写  一天一篇  决定坚持几年 全栈工程师     Python人工智能从入门到精通 装饰器 decorators(专业提高篇) 装饰 ...

  2. c语言版贪吃蛇小游戏

    编译环境:windows 7 64位 编译工具:codeblocks 13.12 备注:未使用graphics.h 声明:个人原创,未经允许,禁止转载!!! 数据结构:双向链表 1.程序未使用grap ...

  3. ZOJ 3544 / HDU 4056 Draw a Mess( 并查集好题 )

    方法参见:http://blog.acmol.com/?p=751 从最后一个线段开始倒着处理(因为之后的线段不会被它之前的线段覆盖),把这条线段所覆盖的所有线段编号合并到一个集合里,并以最左边线段编 ...

  4. JS正则表达式 简单应用

    知识点: 先生成一个正则规则的对象,使用test()对传入的字符串进行验证,返回布尔类型 代码: <!doctype html><html><head> <m ...

  5. BZOJ3244 [Noi2013]树的计数 【数学期望 + 树遍历】

    题目链接 BZOJ3244 题解 不会做orz 我们要挖掘出\(bfs\)序和\(dfs\)序的性质 ①容易知道\(bfs\)序一定是一层一层的,如果我们能确定在\(bfs\)序中各层的断点,就能确定 ...

  6. 1031. 高一学堂 (at)

    题目描述 在美丽的中山纪念中学里面,有一座高一学堂.所谓山不在高,有仙则名:水不在深,有龙则灵.高一学堂,因为有了yxr,就成了现在这个样子 = =. 由于yxr的语言太过雷人,每次他发微往往都会有一 ...

  7. 用HTML5绘制的一个星空特效图

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. 《c程序设计语言》-2.10 不用if-else 转换大小写

    #include <stdio.h> int lower(char a) { int b; b = (a >= 'A' && a <= 'Z') ? (a - ...

  9. P2659 美丽的序列 (单调栈)

    题目链接 Solution 直接考虑单调栈处理出每一个点作为最小值的区间长度. 然后 \(O(n)\) 找一遍最大值即可. 记得开 long long,以及要注意 \(0\) 的问题. Code #i ...

  10. angular.extend(dst,src)的简单示例

    自我认为这个方法跟angular.copy(src,dst)有点相似.在angular.extend({},src)时,就可以画等号.这个src只代表一个对象.代码如下:(注意这个src可以有多个对象 ...