洛谷 P2486 [SDOI2011]染色 树链剖分
题面
题目链接
题目描述

输入输出格式
输入格式

输出格式
对于每个询问操作,输出一行答案。
输入输出样例
输入样例:
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
输出样例:
3
1
2
说明
【数据规模】


【时空限制】
1000ms,128M
思路
看题,操作从a到b的路径上所有点,可以想到树剖。
然而这一题要求的结果有点迷,如果是线段树,第一感觉是要用线段树合并。结构体里面保存 最左端的颜色nowl 和 最右端的颜色nowr ,在两个线段树合并时, 该区间内颜色段数量sum 需要作一下判断:如果左儿子的最右端和右儿子的最左端颜色相同,那么sum应该是左儿子和右儿子的sum之和减1;否则是左儿子和右儿子的sum之和。
基本思路确定了,再看看实际。。。
PushDown与Update
void Update(int p)
{
s(p)=s(p<<1)+s(p<<1|1);
if(nr(p<<1)==nl(p<<1|1)) s(p)--; ///如上所说的判断
nl(p)=nl(p<<1);
nr(p)=nr(p<<1|1);
}
void PushDown(int p)
{
if(t(p))
{
s(p<<1)=s(p<<1|1)=1; ///此时两个儿子的sum都是1
nl(p<<1)=nr(p<<1)=nl(p<<1|1)=nr(p<<1|1)=t(p<<1)=t(p<<1|1)=t(p); ///左、右儿子最左、最右结点,还有懒标记全部变成了现在染上的颜色
t(p)=0;
}
}
Q
本来以为查询操作也是线段树合并,然后写了一半发现不对劲,因为查询的路径上新给定的标号nid是不连续的!不过,nid不连续,我们可以直接判断。
int Ask2(int u,int v)
{
int ans=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
SegmentTree tmp=Ask1(1,nid[top[u]],nid[u]);
ans+=tmp.sum; ///统计答案的时候把单独的这条链的颜色段数量加上
if(tmp.nl==Ask1(1,nid[fa[top[u]]],nid[fa[top[u]]]).nr) ans--; ///考虑到,如果这条链可以和下一条链合并,那必然是他和他的父亲合并,所以这个时候只要判断他和他父亲颜色是否相同,来判断是否要减1
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
ans+=Ask1(1,nid[u],nid[v]).sum;
return ans;
}
AC代码
#include<bits/stdc++.h>
const int maxn=100010;
using namespace std;
int n,m,wt[maxn];
int tot,to[maxn<<1],nxt[maxn<<1],head[maxn];
int son[maxn],fa[maxn],len[maxn],dep[maxn];
int cnt,nid[maxn],nw[maxn],top[maxn];
struct SegmentTree
{
int l,r,sum,nl,nr,tag;
#define l(a) tree[a].l
#define r(a) tree[a].r
#define m(a) ((l(a)+r(a))>>1)
#define len(a) (r(a)-l(a)+1)
#define s(a) tree[a].sum
#define nl(a) tree[a].nl
#define nr(a) tree[a].nr
#define t(a) tree[a].tag
}tree[maxn<<2];
void dfs1(int u,int f,int d)
{
fa[u]=f;dep[u]=d;len[u]=1;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(v==f) continue;
dfs1(v,u,d+1);
len[u]+=len[v];
if(len[v]>len[son[u]]) son[u]=v;
}
}
void dfs2(int p,int t)
{
nid[p]=++cnt;
nw[cnt]=wt[p];
top[p]=t;
if(!son[p]) return;
dfs2(son[p],t);
for(int i=head[p];i;i=nxt[i])
{
int v=to[i];
if(v==fa[p] || v==son[p]) continue;
dfs2(v,v);
}
}
void Update(int p)
{
s(p)=s(p<<1)+s(p<<1|1);
if(nr(p<<1)==nl(p<<1|1)) s(p)--;
nl(p)=nl(p<<1);
nr(p)=nr(p<<1|1);
}
void BuildTree(int p,int l,int r)
{
l(p)=l;r(p)=r;
if(l==r)
{
s(p)=1;
nl(p)=nr(p)=nw[l];
return;
}
BuildTree(p<<1,l,m(p));
BuildTree(p<<1|1,m(p)+1,r);
Update(p);
}
void PushDown(int p)
{
if(t(p))
{
s(p<<1)=s(p<<1|1)=1;
nl(p<<1)=nr(p<<1)=nl(p<<1|1)=nr(p<<1|1)=t(p<<1)=t(p<<1|1)=t(p);
t(p)=0;
}
}
void Change1(int p,int l,int r,int k)
{
if(l<=l(p) && r>=r(p))
{
s(p)=1;
nl(p)=nr(p)=t(p)=k;
return;
}
PushDown(p);
if(l<=m(p)) Change1(p<<1,l,r,k);
if(r>m(p)) Change1(p<<1|1,l,r,k);
Update(p);
}
void Change2(int u,int v,int k)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
Change1(1,nid[top[u]],nid[u],k);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
Change1(1,nid[u],nid[v],k);
}
SegmentTree Ask1(int p,int l,int r)
{
if(l<=l(p) && r>=r(p)) return tree[p];
PushDown(p);
if(r<=m(p)) return Ask1(p<<1,l,r);
else if(l>m(p)) return Ask1(p<<1|1,l,r);
else
{
SegmentTree a=Ask1(p<<1,l,r),b=Ask1(p<<1|1,l,r),tmp;
tmp.nl=a.nl;tmp.nr=b.nr;
tmp.sum=a.sum+b.sum;
if(a.nr==b.nl) tmp.sum--;
return tmp;
}
}
int Ask2(int u,int v)
{
int ans=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]]) swap(u,v);
SegmentTree tmp=Ask1(1,nid[top[u]],nid[u]);
ans+=tmp.sum;
if(tmp.nl==Ask1(1,nid[fa[top[u]]],nid[fa[top[u]]]).nr) ans--;
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
ans+=Ask1(1,nid[u],nid[v]).sum;
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&wt[i]);
for(int i=1;i<n;i++)
{
int u,v;scanf("%d%d",&u,&v);
to[++tot]=v;nxt[tot]=head[u];head[u]=tot;
to[++tot]=u;nxt[tot]=head[v];head[v]=tot;
}
dfs1(1,1,1);
dfs2(1,1);
BuildTree(1,1,n);
for(int i=1;i<=m;i++)
{
char ch;cin>>ch;
int u,v,k;scanf("%d%d",&u,&v);
if(ch=='C')
{
scanf("%d",&k);
Change2(u,v,k);
}
else printf("%d\n",Ask2(u,v));
}
return 0;
}
总结与拓展
感觉有点没讲清楚。这道题写完应该是对树剖有了进一步的巩固。
洛谷 P2486 [SDOI2011]染色 树链剖分的更多相关文章
- BZOJ2243 洛谷2486 [SDOI2011]染色 树链剖分
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2243 题目传送门 - 洛谷2486 题意概括 一棵树,共n个节点. 让你支持以下两种操作,共m次操 ...
- Luogu P2486 [SDOI2011]染色(树链剖分+线段树合并)
Luogu P2486 [SDOI2011]染色 题面 题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例: 6 5 2 2 1 2 1 1 1 ...
- luogu题解P2486[SDOI2011]染色--树链剖分+trick
题目链接 https://www.luogu.org/problemnew/show/P2486 分析 看上去又是一道强行把序列上问题搬运到树上的裸题,然而分析之后发现并不然... 首先我们考虑如何在 ...
- 洛谷P2486 [SDOI2011]染色 题解 树链剖分+线段树
题目链接:https://www.luogu.org/problem/P2486 首先这是一道树链剖分+线段树的题. 线段树部分和 codedecision P1112 区间连续段 一模一样,所以我们 ...
- 洛谷 P2486 [SDOI2011]染色(树链剖分+线段树)
题目链接 题解 比较裸的树链剖分 好像树链剖分的题都很裸 线段树中维护一个区间最左和最右的颜色,和答案 合并判断一下中间一段就可以了 比较考验代码能力 Code #include<bits/st ...
- 洛谷P2486 [SDOI2011]染色(树链剖分+线段树判断边界)
[题目链接] [思路]: 涉及到树上区间修改操作,所以使用树链剖分,涉及到区间查询,所以使用线段树. update操作时,就正常操作,难点在于query操作的计数. 因为树链剖分的dfs序只能保证一条 ...
- 洛谷$P2486\ [SDOI2011]$染色 线段树+树链剖分
正解:线段树+树链剖分 解题报告: 传送门$QwQ$ 其实是道蛮板子的题,,,但因为我写得很呆然后写了贼久之后发现想法有问题要重构,就很难受,就先写个题解算了$kk$ 考虑先跑个树剖,然后按$dfn$ ...
- 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 ...
随机推荐
- C#可扩展编程之MEF(三):导出类的方法和属性
前面说完了导入和导出的几种方法,如果大家细心的话会注意到前面我们导出的都是类,那么方法和属性能不能导出呢???答案是肯定的,下面就来说下MEF是如何导出方法和属性的. 还是前面的代码,第二篇中已经 ...
- MapReduce:详解Shuffle(copy,sort,merge)过程(转)
Shuffle过程是MapReduce的核心,也被称为奇迹发生的地方.要想理解MapReduce, Shuffle是必须要了解的.我看过很多相关的资料,但每次看完都云里雾里的绕着,很难理清大致的逻辑, ...
- 【vue】imitate-beautiful-thing
我从未见过这么美妙的项目,当然与我接触的项目少有关,但是这个项目满满的艺术气息,让人沉醉,让人忍不住的去研究代码. 先放项目地址:https://github.com/eidonlon/imitate ...
- 系统io统计
$ cat /proc/diskstats sda sda1 sda2 gg- gg- gg- 主号 次号 名称 成功读 合并读 扇区读 读时间 每一列的含义分别为: 第一列为 设备号 (nu ...
- tmux使用教程
1.安装 2.操作 如何操作快捷键呢? 比如新建一个窗口的命令是:ctrl+b+c 那么,先按住ctrl不放,接着按下b键,然后ctrl和b键都完全松开后,再立马按下c键. 3.使用命令行 tmux ...
- spring cloud深入学习(二)-----服务注册中心spring cloud eureka
服务治理 主要用来实现各个微服务实例的自动化注册与发现,为啥需要这玩意呢?在一开始比如A系统调用B服务,可能通过手工维护B服务的实例,并且还得采用负载均衡等方式,这些全部都得需要手工维护,等后面系统越 ...
- LintCode_50 数组剔除元素后的乘积
题目 给定一个整数数组A. 定义B[i] = A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1], 计算B的时候请不要使用除法. 样例 给出A=[1, 2, 3], ...
- Java问题解读系列之String相关---String类为什么是final的?
今天看到一篇名为<Java开发岗位面试题归类汇总>的博客,戳进去看了一下题目,觉得有必要夯实一下基本功了,所以打算边学边以博客的形式归纳总结,每天一道题, 并将该计划称为java问题解读系 ...
- 操作系统Lab1 详解(boot|kern/debug)
总体 : boot kern libs tools boot asm.h bootmain.c bootasm.S asm.h 汇编头文件 SEG_NULLASM 定义一个空段描述符 SEG_ASM ...
- 洛谷P1315 [NOIP2011提高组Day2T3] 观光公交
P1315 观光公交 题目描述 风景迷人的小城Y 市,拥有n 个美丽的景点.由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供更便捷的交通服务.观光公交车在第 0 分钟出现在 1号 ...