「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 ...
随机推荐
- KindEditor富文本编辑器使用
我的博客本来打算使用layui的富文本编辑器,但是出了一个问题,无法获取编辑器内容,我参考官方文档,获取内容也就那几个方法而已,但是引入进去后始终获取的值为空,百度和bing都试过了,但是始终还是获取 ...
- UIImagePickerController - 官方文档说明
使用UIImagePickerController对象的步骤: 1)验证设备是否能从目标源获取内容,通过调用 + (BOOL)isSourceTypeAvailable:(UIImagePickerC ...
- 调用Runtime.getruntime 下的exec方法时,有",<,|时该怎么办?
今天写一个用到编译的程序,遇到了问题. 在调用runtime.exec("javac HelloWorld.java");运行完美,也就是有生成.class. 而到了runtime ...
- 2019-04-03 搭建Mybatis环境
1. 配置pom.xml依赖 <dependency> <groupId>org.mybatis</groupId> <artifactId>mybat ...
- 通过CONN_MAX_AGE优化Django的数据库连接
上周对我们用Django+Django-rest-framework提供的一套接口进行了压力测试.压测的过程中,收到DBA通知——数据库连接数过多,希望我们优化下程序.具体症状就是,如果设置mysql ...
- Delphi Create(nil), Create(self), Create(Application)的区别
最近的项目中经常在程序中动态创建控件,势必用到Create. 但是随之而来的问题就是动态创建的控件是否可以正确的释放内存? 以及 Create(nil), Create(self), Create(A ...
- js DOM操作 容易犯的错误
这样一段html片段 <select class="form-control" id="course_chapter" onchange="fi ...
- Android NDK(C++) 双进程守护
双进程守护如果从进程管理器观察会发现新浪微博.支付宝和QQ等都有两个以上相关进程,其中一个就是守护进程,由此可以猜到这些商业级的软件都采用了双进程守护的办法. 什么是双进程守护呢?顾名思义就是两个进程 ...
- [SCOI2009] 迷路
题目类型:拆点, 矩阵快速幂 转化为矩阵快速幂,好题! 传送门:>Here< 题意:给出邻接矩阵,求\(1\)到\(N\)恰好长度为\(T\)的路径方案数 解题思路 如果题目给出的是一个\ ...
- Input标签使用整理
0 写在前面 对于程序而言I/O是一个程序的重要组成部分.程序的输入.输出接口,指定了程序与用户之间的交互方式.对于前端开发而言,input标签也有着其重要地位,它为用户向服务端提交数据提供了可能. ...