洛谷 P2486 [SDOI2011]染色/bzoj 2243: [SDOI2011]染色 解题报告
[SDOI2011]染色
题目描述
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
输入输出格式
输入格式
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
输出格式
对于每个询问操作,输出一行答案。
说明
数N<=105,操作数M<=105,所有的颜色C为整数且在[0, 10^9]之间。
本来想复习一下树剖的,谁知道这题打起来超恶心。。
线段树上维护一下区间左端点颜色和右端点颜色,多的减掉就行啦
Code:
#include <cstdio>
#define ls id<<1
#define rs id<<1|1
int min(int x,int y){return x<y?x:y;}
int max(int x,int y){return x>y?x:y;}
const int N=2e5+10;
int head[N],to[N],Next[N],cnt;
void add(int u,int v)
{
to[++cnt]=v;Next[cnt]=head[u];head[u]=cnt;
}
int top[N],dep[N],siz[N],f[N],dfn[N],ws[N],ha[N],dfs_clock,n,m;
void dfs1(int now)
{
++siz[now];
for(int i=head[now];i;i=Next[i])
{
int v=to[i];
if(f[now]!=v)
{
dep[v]=dep[now]+1;
f[v]=now;
dfs1(v);
siz[now]+=siz[v];
if(siz[ws[now]]<siz[v])
ws[now]=v;
}
}
}
void dfs2(int now,int anc)
{
dfn[now]=++dfs_clock;
ha[dfs_clock]=now;
top[now]=anc;
if(ws[now]) dfs2(ws[now],anc);
for(int i=head[now];i;i=Next[i])
if(!dfn[to[i]])
dfs2(to[i],to[i]);
}
int clo[N],lc[N<<2],rc[N<<2],sum[N<<2],lazy[N<<2];
void updata(int id)//保证不为叶子
{
sum[id]=sum[ls]+sum[rs]-(rc[ls]==lc[rs]);
lc[id]=lc[ls];
rc[id]=rc[rs];
}
void build(int id,int l,int r)
{
if(l==r)
{
lc[id]=rc[id]=clo[ha[l]];
sum[id]=1;
return;
}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
updata(id);
}
void pushdown(int id)//保证不为叶子
{
if(lazy[id])
{
lazy[ls]=lazy[rs]=lc[ls]=lc[rs]=rc[ls]=rc[rs]=lazy[id];
sum[ls]=sum[rs]=1;
lazy[id]=0;
}
}
int line=0;
void change(int id,int l,int r,int L,int R,int color)
{
if(L!=R) pushdown(id);
if(l==L&&r==R)
{
lazy[id]=lc[id]=rc[id]=color;
sum[id]=1;
return;
}
int Mid=L+R>>1;
if(r<=Mid) change(ls,l,r,L,Mid,color);
else if(l>Mid) change(rs,l,r,Mid+1,R,color);
else change(ls,l,Mid,L,Mid,color),change(rs,Mid+1,r,Mid+1,R,color);
updata(id);
}
int query(int id,int l,int r,int L,int R,int &cl,int &cr)
{
if(L!=R) pushdown(id);
if(l==L&&r==R)
{
cl=lc[id],cr=rc[id];
return sum[id];
}
int Mid=L+R>>1,c0,c1;
if(r<=Mid) return query(ls,l,r,L,Mid,cl,cr);
else if(l>Mid) return query(rs,l,r,Mid+1,R,cl,cr);
else return query(ls,l,Mid,L,Mid,cl,c0)+query(rs,Mid+1,r,Mid+1,R,c1,cr)-(rc[ls]==lc[rs]);
}
void t_change(int x,int y,int c)
{
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
{
change(1,dfn[top[x]],dfn[x],1,n,c);
x=f[top[x]];
}
else
{
change(1,dfn[top[y]],dfn[y],1,n,c);
y=f[top[y]];
}
}
change(1,min(dfn[x],dfn[y]),max(dfn[x],dfn[y]),1,n,c);
}
int t_query(int x,int y)
{
int s=0,xc=0,yc=0,cl,cr;
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
{
s+=query(1,dfn[top[x]],dfn[x],1,n,cl,cr);
s-=cr==xc;
xc=cl;
x=f[top[x]];
}
else
{
s+=query(1,dfn[top[y]],dfn[y],1,n,cl,cr);
s-=cr==yc;
yc=cl;
y=f[top[y]];
}
}
s+=query(1,min(dfn[x],dfn[y]),max(dfn[x],dfn[y]),1,n,cl,cr);
if(dfn[x]<dfn[y]) s-=(cl==xc)+(cr==yc);
else s-=(cl==yc)+(cr==xc);
return s;
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("data.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",clo+i);
for(int u,v,i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
dfs1(1),dfs2(1,1);
build(1,1,n);
char op[21];
for(int a,b,c,i=1;i<=m;i++)
{
scanf("%s%d%d",op,&a,&b);
if(op[0]=='C') scanf("%d",&c),t_change(a,b,c);
else printf("%d\n",t_query(a,b));
}
return 0;
}
2018.8.27
洛谷 P2486 [SDOI2011]染色/bzoj 2243: [SDOI2011]染色 解题报告的更多相关文章
- 洛谷 P1291 [SHOI2002]百事世界杯之旅 解题报告
P1291 [SHOI2002]百事世界杯之旅 题目描述 "--在2002年6月之前购买的百事任何饮料的瓶盖上都会有一个百事球星的名字.只要凑齐所有百事球星的名字,就可参加百事世界杯之旅的抽 ...
- 洛谷 P4714 「数学」约数个数和 解题报告
P4714 「数学」约数个数和 题意(假):每个数向自己的约数连边,给出\(n,k(\le 10^{18})\),询问\(n\)的约数形成的图中以\(n\)为起点长为\(k\)的链有多少条(注意每个点 ...
- 洛谷 P4345 [SHOI2015]超能粒子炮·改 解题报告
P4345 [SHOI2015]超能粒子炮·改 题意 求\(\sum_{i=0}^k\binom{n}{i}\),\(T\)组数据 范围 \(T\le 10^5,n,j\le 10^{18}\) 设\ ...
- 洛谷 P1691 有重复元素的排列问题 解题报告
P1691 有重复元素的排列问题 题目描述 设\(R={r_1,r_2,--,r_n}\)是要进行排列的\(n\)个元素.其中元素\(r_1,r_2,--,r_n\)可能相同.使设计一个算法,列出\( ...
- 洛谷 P2746 [USACO5.3]校园网Network of Schools 解题报告
P2746 [USACO5.3]校园网Network of Schools 题目描述 一些学校连入一个电脑网络.那些学校已订立了协议:每个学校都会给其它的一些学校分发软件(称作"接受学校&q ...
- 洛谷 P1121 环状最大两段子段和 解题报告
P1121 环状最大两段子段和 题目描述 给出一段环状序列,即认为\(A_1\)和\(A_N\)是相邻的,选出其中连续不重叠且非空的两段使得这两段和最大. 输入输出格式 输入格式: 第一行是一个正整数 ...
- 洛谷 P1120 小木棍 [数据加强版]解题报告
P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它 ...
- 洛谷 P2336 [SCOI2012]喵星球上的点名 解题报告
P2336 [SCOI2012]喵星球上的点名 题目描述 a180285 幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有 \(N\) 个喵星人,每个喵星人的 ...
- 洛谷 P2862 [USACO06JAN]把牛Corral the Cows 解题报告
P2862 [USACO06JAN]把牛Corral the Cows 题目描述 Farmer John wishes to build a corral for his cows. Being fi ...
随机推荐
- 003---Python基本数据类型--列表
列表 .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px ...
- pwa学习笔记--简介
1. 介绍 Progressive Web App , (渐进式增强 WEB 应用) 简称 PWA ,是提升WebApp的体验的一种新方法,能给用户原生应用的体验. PWA 本质上是 Web App ...
- [拉格朗日反演][FFT][NTT][多项式大全]详解
1.多项式的两种表示法 1.系数表示法 我们最常用的多项式表示法就是系数表示法,一个次数界为\(n\)的多项式\(S(x)\)可以用一个向量\(s=(s_0,s_1,s_2,\cdots,s_n-1) ...
- 【转】Linux系统安装Redis详细过程
本文来源 https://blog.csdn.net/qq_20989105/article/details/76390367 ,转载前请先联系原作者并声明出处. 一.安装gcc 1.Redis在li ...
- [【转】ubuntu 16.10 Server 安装及基本部署
一.Ubuntu Server 16.10 LTS 系统安装 Ubuntu 16.10 分为 桌面版 (desktop)和服务器版(Server).两者对于用户而言,最大的区别在于桌面版有图形操作界面 ...
- 在spring+beranate中多数据源中使用 ThreadLocal ,总结的原理 --费元星
设计模式 首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通过ThreadLocal.set() 到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问 ...
- L008之前课程实战模拟。
L008之前课程实战模拟. . 安装CentOS 6.5 X86_64 . 配置网络 . 用CRT连接服务器 . 更换源http://mirrors.163.com/.help/CentOS6-Bas ...
- 每天一个Linux命令(14):dpkg命令
dpkg命令是Debian Linux系统用来安装.创建和管理软件包的实用工具. 语法: dpkg (选项) (参数) 选项: -i:安装软件包: -r:删除软件包: -P:删除软件包的同时删除其配置 ...
- 从底层带你理解Python中的一些内部机制
下面博文将带你创建一个字节码级别的追踪API以追踪Python的一些内部机制,比如类似YIELDVALUE.YIELDFROM操作码的实现,推式构造列表(List Comprehensions).生成 ...
- tensorflow nmt基本配置(tf-1.4)
随着tensorflow的不断更新,直接按照nmt的教程搭建nmt环境会报错的...因此,需要一些不太好的办法来避免更多的问题出现.tensorflow看来在ubuntu和debian中运行是没有问题 ...