题目描述

输入输出格式

输入格式:

输出格式:

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

输入输出样例

输入样例#1:

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
输出样例#1:

3
1
2

留一点自己思考的时间.

下面开始讲解.

题目大概题意是给出一颗树,树上每个节点都有一个颜色,让你求出一条路径上的颜色段数量,并需要对树进行修改.

看到树,很容易会想到是数据结构的题目.

需要对树上节点信息进行更新,并做到实时查询,这里采用了树链剖分.

树链剖分可以看我之前的讲解:树链剖分.

那么问题就转化成了记录一个区间的颜色段数量.如果用线段树来记录,那么可以直接存下一个节点的颜色段数量.但是当遇到区间的合并时,就需要判断两个合并的区间相连接的部分是否颜色一样. 如果一样,就将合并后两个区间颜色段数量相加再减一,否则直接相加.

但是当树剖部分中有一个跳链的步骤,从一条链跳到另一条链时就出现了两个区间需要合并的问题.为了解决这个问题,可以写一个函数对线段树中的端点的颜色进行单点查询.然后判断合并.

下面是代码:

#include<bits/stdc++.h>
#define mid (left+right>>1)
#define ll(x) (x<<1)
#define rr(x) (x<<1|1)
using namespace std;
const int inf=;
const int N=; int n,m,cn[N+];
int fa[N+],id[N+],son[N+],dep[N+],cs[N+],top[N+],size[N+],idx=;
int sum[N*+],lazy[N*+],lc[N*+],rc[N*+];
int cnt=,last[N+]; struct edge{
int to,next;
}e[N+]; int gi(){
int ans=,f=;char i=getchar();
while(i<''||i>''){if(i=='-')f=-;i=getchar();}
while(i>=''&&i<=''){ans=ans*+i-'';i=getchar();}
return ans*f;
} void add(int x,int y){
e[++cnt].to=y;
e[cnt].next=last[x];
last[x]=cnt;
} void dfs1(int x,int deep,int father){
dep[x]=deep; fa[x]=father; int maxson=-;
for(int i=last[x];i;i=e[i].next){
int to=e[i].to;
if(to!=father){
dfs1(to,deep+,x);
size[x]+=size[to];
if(maxson<size[to]){
son[x]=to;
maxson=size[to];
}
}
}
} void dfs2(int x,int tp){
top[x]=tp; id[x]=++idx; cs[idx]=cn[x];
if(!son[x]) return;
dfs2(son[x],tp);
for(int i=last[x];i;i=e[i].next){
int to=e[i].to;
if(to!=son[x]&&to!=fa[x])
dfs2(to,to);
}
} void pushdown(int root,int left,int right){
lazy[ll(root)]=lazy[rr(root)]=lazy[root];
lc[ll(root)]=lc[rr(root)]=lazy[root];
rc[ll(root)]=rc[rr(root)]=lazy[root];
sum[ll(root)]=sum[rr(root)]=;
lazy[root]=;
} void pushup(int root,int left,int right){
lc[root]=lc[ll(root)]; rc[root]=rc[rr(root)];
int res=sum[ll(root)]+sum[rr(root)];
if(rc[ll(root)]==lc[rr(root)]) res--;
sum[root]=res;
} void build(int root,int left,int right){
if(left==right){
lc[root]=rc[root]=cs[left];
//cout<<root<<' '<<cs[left]<<endl;;
sum[root]=;
return;
}
build(ll(root),left,mid);
build(rr(root),mid+,right);
pushup(root,left,right);
} void updata(int root,int left,int right,int l,int r,int col){
if(l<=left&&right<=r){
sum[root]=; lazy[root]=col;
lc[root]=rc[root]=col;
return;
}
if(lazy[root]) pushdown(root,left,right);
if(l<=mid) updata(ll(root),left,mid,l,r,col);
if(mid<r) updata(rr(root),mid+,right,l,r,col);
pushup(root,left,right);
} void cupdata(int a,int b,int val){
while(top[a]!=top[b]){
if(dep[top[a]]<dep[top[b]]) swap(a,b);
updata(,,n,id[top[a]],id[a],val);
a=fa[top[a]];
}
if(id[a]>id[b]) swap(a,b);
updata(,,n,id[a],id[b],val);
} int qcol(int root,int left,int right,int node){
if(left==right) return lc[root];
if(lazy[root]) pushdown(root,left,right);
if(node<=mid) return qcol(ll(root),left,mid,node);
else return qcol(rr(root),mid+,right,node);
} int query(int root,int left,int right,int l,int r){
if(l<=left&&right<=r) return sum[root];
if(r<left||right<l) return ;
if(lazy[root]) pushdown(root,left,right);
if(r<=mid) return query(ll(root),left,mid,l,r);
else if(mid<l) return query(rr(root),mid+,right,l,r);
else{
int res=query(ll(root),left,mid,l,r)+query(rr(root),mid+,right,l,r);
if(lc[rr(root)]==rc[ll(root)]) res--;
//cout<<res<<endl;
return res;
}
} int cquery(int a,int b){
int res=;
while(top[a]!=top[b]){
if(dep[top[a]]<dep[top[b]]) swap(a,b);
res+=query(,,n,id[top[a]],id[a]);
int LC=qcol(,,n,id[top[a]]),RC=qcol(,,n,id[fa[top[a]]]);
if(LC==RC) res--;
a=fa[top[a]];
}
if(id[a]>id[b]) swap(a,b);
res+=query(,,n,id[a],id[b]);
printf("%d\n",res);
} int main(){
n=gi(); m=gi(); int x , y , val ;char flag;
for(int i=;i<=n;i++) cn[i]=gi();
for(int i=;i<=n;i++) size[i]=;
for(int i=;i<n;i++){
x=gi(); y=gi();
add(x,y); add(y,x);
}
dfs1(,,-); dfs2(,); build(,,n);
//for(int i=1;i<=n;i++) cout<<i<<' '<<cs[i]<<endl;
for(int i=;i<=m;i++){
cin>>flag;
if(flag=='C'){
x=gi(); y=gi(); val=gi();
cupdata(x,y,val);
}
if(flag=='Q'){
x=gi(); y=gi();
cquery(x,y);
}
}
return ;
}

[SDOI2011] 染色(Luogu 2486)的更多相关文章

  1. [Luogu 2486] SDOI2011 染色

    [Luogu 2486] SDOI2011 染色 树剖水题,线段树维护. 详细题解不写了. 我只想说我写的线段树又变漂亮了qwq #include <algorithm> #include ...

  2. Luogu P2486 [SDOI2011]染色(树链剖分+线段树合并)

    Luogu P2486 [SDOI2011]染色 题面 题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例: 6 5 2 2 1 2 1 1 1 ...

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

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

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

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

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

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

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

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

  7. bzoj2243:[SDOI2011]染色

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

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

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

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

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

随机推荐

  1. 最小生成树——prim

    prim:逐“点”生成最小生成树 与Dijkstra不同的是:加入点到生成树中,不要考虑与源点的距离,而是考虑与生成树的距离 #include <iostream> #include &l ...

  2. Python—列表(一个“打了激素”的数组)

    我们在C语言中会使用数组来将一大堆数据类型一样的数据挨个摆在一起,但是数组有一个基本的要求,就是数据类型必须是一致的,我们知道Python的变量由于没有数据类型,也就是说Python没有数组这一概念, ...

  3. 新人学PHP,认为手动搭建环境而苦恼吗?这篇文章告诉你多简单!

    本教程适用于初学PHP,想了解手动搭建PHP环境的童鞋. 一键环境和高手勿喷. 本教程以下列版本软件为例: 所需软件目录 我在这里的目录结构是(个人习惯) 安装与配置 apache 双击安装Apach ...

  4. 第三部分shell编程3(shell脚本2)

    7. if 判断一些特殊用法 if [ -z $a ] 这个表示当变量a的值为空时会怎么样if grep -q '123' 1.txt; then 表示如果1.txt中含有'123'的行时会怎么样if ...

  5. Tiny4412 LED 程序

    package cn.hyc.led; import android.os.Bundle; import android.app.Activity; import android.view.Menu; ...

  6. Oracle基础 表分区

    Oracle基础 表分区 一.表分区 (一)表分区的分类 1.范围分区(range) 2.散列分区(hash) 3.列表分区(list) 4.复合分区:范围-哈希(range-hash).范围-列表( ...

  7. change object keys & UpperCase & LowerCase

    change object keys & UpperCase & LowerCase .toLocaleUpperCase(); && .toLocaleLowerCa ...

  8. ASP.Net MVC+Ibaties架构

    1.配置Ibaties首先在DLL引用中添加Ibaties相关引用:IBatisNet.Common.dll;IBatisNet.Common.Logging.Log4Net.dll;IBatisNe ...

  9. 第49天:封装自己的scrollTop

    一.scroll家族 offset 自己的偏移scroll滚动的 scrollTop和scrollLeftscrollTop 被卷去的头部当滑动滚轮浏览网页的时候,网页隐藏在屏幕上方的距离二.页面滚动 ...

  10. Python re(正则表达式)模块

    python正则表达式 正则表达式是一个特殊的字符序列,它能帮助我们方便的检查一个字符串是否与某种模式匹配.Python自1.5版本起增加了re模块,它提供Perl风格的正则表达式模式.re模块使Py ...