「luogu2486」[SDOI2011] 染色
https://www.luogu.org/problemnew/show/P2486
轻重链剖分后,问题转化为一个链上的问题;
线段树维护区间内的颜色段数量,左端点、右端点的颜色;
线段树注意事项 {
合并时判断两个区间的相邻端点是否相同;
查询时同上,但要注意是否两段是不是都在查询区间内;
lazy_tag和更新颜色,嘻嘻嘻。
}
p.s 树上查询颜色段要判断两条链的端点是否颜色相同;
特别地,对于在同一条链上的两个节点之间的查询,要判断两个点和与它相邻点的颜色是否相同。
代码如下 :
// 15owzLy1
//luogu2486.cpp
//2018 09 26 18:38:11
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson tl, mid, rt<<1
#define rson mid+1, tr, rt<<1|1
typedef long long ll;
typedef double db;
using namespace std; const int N = ;
struct node { int l, r, cnt; };
struct info {
int next, to;
}edge[N<<];
int head[N], dfn[N], size[N], hson[N], fa[N], dep[N], q, n;
int front[N], cl[N]; template<typename T>inline void read(T &x_) {
x_=;bool f_=;char c_=getchar();
while(c_<''||c_>''){f_|=(c_=='-');c_=getchar();}
while(c_>=''&&c_<=''){x_=(x_<<)+(x_<<)+(c_^);c_=getchar();}
x_=f_?-x_:x_;
} struct Segment_Tree {
node t[N<<]; int lazy[N<<];
inline void push_up(int rt) {
t[rt].cnt=t[rt<<].cnt+t[rt<<|].cnt;
if(t[rt<<].r==t[rt<<|].l) t[rt].cnt--;
t[rt].l=t[rt<<].l, t[rt].r=t[rt<<|].r;
}
inline void spread(int rt) {
t[rt<<].cnt=; t[rt<<|].cnt=;
t[rt<<].l=t[rt<<|].r=t[rt<<].r=t[rt<<|].l=
lazy[rt<<]=lazy[rt<<|]=lazy[rt];
lazy[rt]=;
}
void update(int del, int l, int r, int tl, int tr, int rt) {
if(l<=tl&&tr<=r) {
t[rt].cnt=; t[rt].l=t[rt].r=lazy[rt]=del;
return ;
}
if(lazy[rt]) spread(rt);
int mid=(tl+tr)>>;
if(mid>=l) update(del, l, r, lson);
if(mid<r) update(del, l, r, rson);
push_up(rt);
}
int query(int l, int r, int tl, int tr, int rt) {
if(l<=tl&&tr<=r) return t[rt].cnt;
if(lazy[rt]) spread(rt);
int mid=(tl+tr)>>, res=, k=;
if(mid>=l) res+=query(l, r, lson), ++k;
if(mid<r) res+=query(l, r, rson), ++k;
if(t[rt<<].r==t[rt<<|].l&&k>=) res--;
return res;
}
int ask_cl(int pos, int tl, int tr, int rt) {
if(tl==tr) return t[rt].l;
if(lazy[rt]) spread(rt);
int mid=(tl+tr)>>;
if(mid>=pos) return ask_cl(pos, lson);
else return ask_cl(pos, rson);
}
}T; inline void jb(int u, int v) {
edge[++edge[].to].to=v;
edge[edge[].to].next=head[u];
head[u]=edge[].to;
} void dfs(int u) {
size[u]=;
for(int i=head[u];i;i=edge[i].next) {
int v=edge[i].to;
if(v==fa[u]) continue;
fa[v]=u; dep[v]=dep[u]+;
dfs(v);
size[u]+=size[v];
if(size[hson[u]]<size[v]) hson[u]=v;
}
} inline void dfs_(int u, int father) {
dfn[u]=++dfn[]; front[u]=father;
if(hson[u]) dfs_(hson[u], father);
for(int i=head[u];i;i=edge[i].next) {
int v=edge[i].to;
if(v==fa[u]||v==hson[u]) continue;
dfs_(v, v);
}
} inline void update(int u, int v, int del) {
while(front[u]!=front[v]) {
if(dep[front[u]]>dep[front[v]]) swap(u, v);
T.update(del, dfn[front[v]], dfn[v], , n, );
v=fa[front[v]];
}
if(dep[u]>dep[v]) swap(u, v);
T.update(del, dfn[u], dfn[v], , n, );
} inline int query(int u, int v) {
int res=, clu=-, clv=-, tmp, k=;
while(front[u]!=front[v]) {
if(dep[front[u]]>dep[front[v]])
swap(u, v), swap(clu, clv);
res+=T.query(dfn[front[v]], dfn[v], , n, );
tmp=T.ask_cl(dfn[v], , n, );
if(clv==tmp) --res;
clv=T.ask_cl(dfn[front[v]], , n, );
v=fa[front[v]];
}
if(dep[u]>dep[v])
swap(u, v), swap(clu, clv);
if(clu==T.ask_cl(dfn[u], , n, )) res--, ++k;
if(clv==T.ask_cl(dfn[v], , n, )) res--, ++k;
res+=T.query(dfn[u], dfn[v], , n, );
return res;
} int main() {
#ifndef ONLINE_JUDGE
freopen("luogu2486.in","r",stdin);
freopen("luogu2486.out","w",stdout);
#endif
int x, y, z; char opt[];
read(n), read(q);
for(int i=;i<=n;i++) read(cl[i]);
for(int i=;i<n;i++) read(x), read(y), jb(x, y), jb(y, x);
dep[]=;
dfs(); dfs_(,);
for(int i=;i<=n;i++) T.update(cl[i], dfn[i], dfn[i], , n, );
while(q--) {
scanf("%s", opt); read(x), read(y);
if(opt[]=='Q') printf("%d\n", query(x, y));
else read(z), update(x, y, z);
}
return ;
}
「luogu2486」[SDOI2011] 染色的更多相关文章
- 「HAOI2018」染色 解题报告
「HAOI2018」染色 是个套路题.. 考虑容斥 则恰好为\(k\)个颜色恰好为\(c\)次的贡献为 \[ \binom{m}{k}\sum_{i\ge k}(-1)^{i-k}\binom{m-k ...
- Loj #3111. 「SDOI2019」染色
Loj #3111. 「SDOI2019」染色 题目描述 给定 \(2 \times n\) 的格点图.其中一些结点有着已知的颜色,其余的结点还没有被染色.一个合法的染色方案不允许相邻结点有相同的染色 ...
- # 「NOIP2010」关押罪犯(二分图染色+二分答案)
「NOIP2010」关押罪犯(二分图染色+二分答案) 洛谷 P1525 描述:n个罪犯(1-N),两个罪犯之间的仇恨值为c,m对仇恨值,求怎么分配使得两件监狱的最大仇恨值最小. 思路:使最大xxx最小 ...
- 「JSOI2015」染色问题
「JSOI2015」染色问题 传送门 虽然不是第一反应,不过还是想到了要容斥. 题意转化:需要求满足 \(N + M + C\) 个条件的方案数. 然后我们就枚举三个数 \(i, j, k\) ,表示 ...
- 「UOJ351」新年的叶子
「UOJ351」新年的叶子 题目描述 有一棵大小为 \(n\) 的树,每次随机将一个叶子染黑,可以重复染,问期望染多少次后树的直径会缩小. \(1 \leq n \leq 5 \times 10^5\ ...
- 「NOI2016」区间 解题报告
「NOI2016」区间 最近思维好僵硬啊... 一上来就觉得先把区间拆成两个端点进行差分,然后扫描位置序列,在每个位置维护答案,用数据结构维护当前位置的区间序列,但是不会维护. 于是想研究性质,想到为 ...
- 「ZJOI2019」语言 解题报告
「ZJOI2019」语言 3个\(\log\)做法比较简单,但是写起来还是有点麻烦的. 大概就是树剖把链划分为\(\log\)段,然后任意两段可以组成一个矩形,就是个矩形面积并,听说卡卡就过去了. 好 ...
- 「CH6901」骑士放置
「CH6901」骑士放置 传送门 将棋盘黑白染色,发现"日"字的两个顶点刚好一黑一白,构成一张二分图. 那么我们将黑点向源点连边,白点向汇点连边,不能同时选的一对黑.白点连边. 当 ...
- 「CH6801」棋盘覆盖
「CH6801」棋盘覆盖 传送门 考虑将棋盘黑白染色,两个都无障碍的相邻的点之间连边,边的容量都为1,然后就求一次最大匹配即可 参考代码: #include <cstring> #incl ...
随机推荐
- IDEA+Maven+各个分支代码进行合并
各个模块的分支代码进行合并到一起:https://blog.csdn.net/xsj_blog/article/details/79198502
- Nero8刻录引导系统光盘镜像图文教程
刻录可引导的Windows系统光盘一直是电脑使用者较为需要的,今天,倡萌抽空写了这篇图文教程,希望对于菜鸟级的朋友有所帮助,大虾请飘过.本教程以最为强大的刻录软件Nero 8做为工具(其他版本的Ner ...
- Linux内存管理 (4)分配物理页面
专题:Linux内存管理专题 关键词:分配掩码.伙伴系统.水位(watermark).空闲伙伴块合并. 我们知道Linux内存管理是以页为单位进行的,对内存的管理是通过伙伴系统进行. 从Linux内存 ...
- left join inner join 区别
left 以左表为准,左表在右表没有对应的记录,也为显示(右表字段填空). inner 需要满足两张表都有记录. 不管哪种join 一对多最终的结局 只会是多条记录
- iOS开发基础-图片切换(4)之懒加载
延续:iOS开发基础-图片切换(3),对(3)里面的代码用懒加载进行改善. 一.懒加载基本内容 懒加载(延迟加载):即在需要的时候才加载,修改属性的 getter 方法. 注意:懒加载时一定要先判断该 ...
- elementUi源码解析(1)--项目结构篇
因为在忙其他事情好久没有更新iview的源码,也是因为后面的一些组件有点复杂在考虑用什么方式把复杂的功能逻辑简单的展示出来,还没想到方法,突然想到element的组件基本也差不多,内部功能的逻辑也差不 ...
- Django自带的用户认证auth模块
一.介绍 基本上在任何网站上,都无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册.用户登录.用户认证.注销.修改密码等功能. 使用Django,我们可以不需要自己写这些功能,因为Dj ...
- P2495 [SDOI2011]消耗战 lca倍增+虚树+树形dp
题目:给出n个点的树 q次询问 问切断 k个点(不和1号点联通)的最小代价是多少 思路:树形dp sum[i]表示切断i的子树中需要切断的点的最小代价是多少 mi[i]表示1--i中的最小边权 ...
- [HDU5969] 最大的位或
题目类型:位运算 传送门:>Here< 题意:给出\(l\)和\(r\),求最大的\(x|y\),其中\(x,y\)在\([l,r]\)范围内 解题思路 首先让我想到了前面那题\(Bits ...
- MAGENTO for XAMPP install config -搬家配置与安装配置
MEGENTO . 2.2.3 . 支持 PHP version is 7.0.2|7.0.4|~7.0.6|~7.1.0 虚拟机主机配置 环境扩展配置 其他错误 httpd-conf —— ...