【BZOJ】2243 [SDOI2011]染色
【算法】树链剖分+线段树
【题解】
树链剖分算法:http://www.cnblogs.com/onioncyc/p/6207462.html
定义线段树结构体有l,r,lc,rc,sum,data。
lc表示左端颜色,rc表示右端颜色,sum表示颜色种类,data表示区间置为同一个数的标记。
修改的时候要上推和下传,查询的时候要下传。
我的写法是打lazy标记的时候顺便把子树的其它参数都修改完毕,方便直接调用。
访问到有lazy标记的子树时把标记下传给左右子树并修改左右子树的其他参数。
左右端颜色相同的处理方法见:http://blog.csdn.net/u011645923/article/details/43087133
还是注意树链剖分后操作要使用新编号pos[i]。
#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
int read()
{
char c;int s=,t=;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
const int maxn=;
int first[maxn],size[maxn],deep[maxn],f[maxn],top[maxn],pos[maxn],LC,RC,n,m,tot,dfsnum,a[maxn];
struct edge{int u,v,from;}e[maxn*];
struct tree{int lc,rc,sum,l,r,data;}t[maxn*];
void insert(int u,int v)
{tot++;e[tot].u=u;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
void dfs1(int x,int fa)
{
size[x]=;
for(int i=first[x];i;i=e[i].from)
if(e[i].v!=fa)
{
int y=e[i].v;
f[y]=x;
deep[y]=deep[x]+;
dfs1(y,x);
size[x]+=size[y];
}
}
void dfs2(int x,int tp,int fa)
{
int k=;
pos[x]=++dfsnum;
top[x]=tp;
for(int i=first[x];i;i=e[i].from)
if(e[i].v!=fa&&size[e[i].v]>size[k])k=e[i].v;
if(k==)return;
dfs2(k,tp,x);
for(int i=first[x];i;i=e[i].from)
if(e[i].v!=fa&&e[i].v!=k)dfs2(e[i].v,e[i].v,x);
}
void build(int k,int l,int r)
{
t[k].l=l;t[k].r=r;
if(l==r){t[k].lc=;t[k].rc=;t[k].sum=;t[k].data=;return;}
else
{
int mid=(l+r)>>;
build(k<<,l,mid);
build(k<<|,mid+,r);
}
}
void pushdown(int k)
{
if(t[k].data)
{
t[k<<].sum=t[k<<|].sum=;
t[k<<].data=t[k<<|].data=t[k].data;
t[k<<].lc=t[k<<].rc=t[k].data;
t[k<<|].lc=t[k<<|].rc=t[k].data;
}
t[k].data=;
}
void pushup(int k)
{
t[k].lc=t[k<<].lc;
t[k].rc=t[k<<|].rc;
t[k].sum=t[k<<].sum+t[k<<|].sum;
if(t[k<<].rc==t[k<<|].lc)t[k].sum--;
}
void change(int k,int l,int r,int x)//区间修改需要上推&&下传
{
pushdown(k);
int left=t[k].l,right=t[k].r;
if(l<=left&&right<=r){t[k].data=x;t[k].sum=;t[k].lc=t[k].rc=x;}
else
{
int mid=(left+right)>>;
if(l<=mid)change(k<<,l,r,x);
if(r>mid)change(k<<|,l,r,x);
pushup(k);
}
}
int ask(int k,int l,int r)//区间查询只需要下传
{
pushdown(k);
int left=t[k].l,right=t[k].r;
if(l==left)LC=t[k].lc;
if(r==right)RC=t[k].rc;
if(l<=left&&right<=r){return t[k].sum;}
else
{
int mid=(left+right)>>,sums=,ok=;
if(l<=mid)sums=ask(k<<,l,r),ok++;
if(r>mid)sums+=ask(k<<|,l,r),ok++;
if(ok==&&t[k<<].rc==t[k<<|].lc)sums--;//只取一边的话就不需要判断了
return sums;
}
}
void update(int x,int y,int z)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])swap(x,y);
change(,pos[top[x]],pos[x],z);//!!!
x=f[top[x]];
}
if(pos[x]>pos[y])swap(x,y);
change(,pos[x],pos[y],z);
}
int solve(int x,int y)
{
int sums=,ansx=,ansy=;//分别表示x和y的左端点颜色
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])swap(x,y),swap(ansx,ansy);
sums+=ask(,pos[top[x]],pos[x]);
if(RC==ansx)sums--;
ansx=LC;
x=f[top[x]];
}
if(pos[x]>pos[y])swap(x,y),swap(ansx,ansy);
sums+=ask(,pos[x],pos[y]);
if(ansx==LC)sums--;
if(ansy==RC)sums--;
return sums;
}
int main()
{
n=read();m=read();
for(int i=;i<=n;i++)a[i]=read();
for(int i=;i<n;i++)
{
int u=read(),v=read();
insert(u,v);
insert(v,u);
}
dfs1(,-);dfs2(,,-);
build(,,n);
for(int i=;i<=n;i++)update(i,i,a[i]+);//颜色+1避免0的问题
for(int i=;i<=m;i++)
{
char c=getchar();
while(!(c=='C'||c=='Q'))c=getchar();
if(c=='C')
{
int x=read(),y=read(),z=read();
update(x,y,z+);
}
else
{
int x=read(),y=read();
printf("%d\n",solve(x,y));
}
}
return ;
}
【BZOJ】2243 [SDOI2011]染色的更多相关文章
- BZOJ 2243: [SDOI2011]染色 [树链剖分]
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6651 Solved: 2432[Submit][Status ...
- bzoj 2243 [SDOI2011]染色(树链剖分,线段树)
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4637 Solved: 1726[Submit][Status ...
- Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5020 Solved: 1872[Submit][Status ...
- bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 7925 Solved: 2975[Submit][Status ...
- bzoj 2243: [SDOI2011]染色 (树链剖分+线段树 区间合并)
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9854 Solved: 3725[Submit][Status ...
- BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...
- BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并
2243: [SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数 ...
- bzoj 2243 [SDOI2011]染色(树链剖分+线段树合并)
[bzoj2243][SDOI2011]染色 2017年10月20日 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询 ...
- 洛谷 P2486 [SDOI2011]染色/bzoj 2243: [SDOI2011]染色 解题报告
[SDOI2011]染色 题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同 ...
- BZOJ 2243 [SDOI2011]染色 (树链剖分)(线段树区间修改)
[SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 6870 Solved: 2546[Submit][Status][Disc ...
随机推荐
- MQTT协议-----订阅
MQTT协议笔记之订阅 http://www.blogjava.net/yongboy/archive/2014/04/12/412351.html MQTT - chszs的专栏 h ...
- week1词频统计
使用java完成对txt格式的英文短片进行字符提取及统计. package nenu.softWareProject; import java.io.*;import java.util.*; pub ...
- BZOJ4950 Wf2017Mission Improbable(二分图匹配)
先给每个非零格子-1以满足俯视图不变.于是就相当于要求每行每列最大值不变.能减少剩余箱子的唯一方法是在要求相同的行列的交叉处放箱子以同时满足两个需求.给这些行列连边跑二分图匹配即可.注意必须格子初始时 ...
- Qt Widgets、QML、Qt Quick的区别
Qt Widgets.QML.Qt Quick的区别 简述 看了之前关于 QML 的一些介绍,很多人难免会有一些疑惑: Q1:QML 和 Qt Quick 之间有什么区别? Q2:QtQuick 1. ...
- 【刷题】LOJ 6041 「雅礼集训 2017 Day7」事情的相似度
题目描述 人的一生不仅要靠自我奋斗,还要考虑到历史的行程. 历史的行程可以抽象成一个 01 串,作为一个年纪比较大的人,你希望从历史的行程中获得一些姿势. 你发现在历史的不同时刻,不断的有相同的事情发 ...
- YOLO v1之总结篇(linux+windows)
YOLO出自2016 CVPR You Only Look Once:Unified, Real-Time Object Detection,也是一个非常值得学习的框架,不得不说facebook的技术 ...
- 【BZOJ1176】Mokia(CDQ分治)
[BZOJ1176]Mokia(CDQ分治) 题面 BZOJ权限题啊,,,, dbzoj真好 Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的 ...
- Alpha 冲刺 —— 十分之一
队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作,对多个目标检测及文字识别模型进行评估.实验,选取较 ...
- redis2.4.conf配置文件中文释意
# Redis示例配置文件 # 注意单位问题:当需要设置内存大小的时候,可以使用类似1k.5GB.4M这样的常见格式: # # 1k => 1000 bytes # 1kb => 1024 ...
- Hbase(四) 过滤器查询
引言:过滤器的类型很多,但是可以分为两大类——比较过滤器,专用过滤器过滤器的作用是在服务端判断数据是否满足条件,然后只将满足条件的数据返回给客户端: 一.hbase过滤器的分类 1.比较过滤器 行键过 ...