【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 ...
随机推荐
- jdbc 5.0
1.事务 事务将单个SQL语句或一组SQL语句视为一个逻辑单元,如果任何语句失败,整个事务将失败. jdbc的MySQL驱动程序中的事务默认是自动提交. 默认情况下,每个SQL语句在完成后都会提交到数 ...
- 2nd 四人小组项目的进一步分析
组长:林莉 组员:王东涵.宫丽君.胡丽娜 项目选题:车辆管理系统(附加相关员工管理) 项目期限:暂定十周 一.NABCD模型 N-Need 需求分析及相应功能设置 需求概述: 管理库中车辆信息.相关人 ...
- MySQL存储引擎InnoDB与Myisam
InnoDB与Myisam的六大区别 InnoDB与Myisam的六大区别 MyISAM InnoDB 构成上的区别: 每个MyISAM在磁盘上存储成三个文件.第一个 文件的名字以表的名字开始,扩展名 ...
- Kafka发布订阅消息
Maven <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-cli ...
- 第199天:js---扩充内置对象功能总结
一.数组 1.删除数组中指定索引的数据 /** 删除数组中指定索引的数据 **/ Array.prototype.deleteAt = function (index) { if (index < ...
- 洛谷 P1401 城市(二分+网络流)
题目描述 N(2<=n<=200)个城市,M(1<=m<=40000)条无向边,你要找T(1<=T<=200)条从城市1到城市N的路,使得最长的边的长度最小,边不能 ...
- [NOI2017]蚯蚓排队 hash
题面:洛谷 题解: 我们暴力维护当前所有队伍内的所有子串(长度k = 1 ~ 50)的出现次数. 把每个子串都用一个hash值来表示,每次改变队伍形态都用双向链表维护,并暴力更新出现次数. 现在考虑复 ...
- Ubuntu上搭建比特币运行环境
Ubuntu版本:16.04.3 Bitcoin Core版本:0.16 1. 比特币运行依赖的开源库 (1)必须依赖的库 库 目的 描述 libssl 加密 随机数生成,椭圆曲线加密算法 libbo ...
- 【BZOJ4516】生成魔咒(后缀自动机)
[BZOJ4516]生成魔咒(后缀自动机) 题面 BZOJ Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. ...
- OpenFlow协议中如何提高交换机流表的匹配成功率
写在前面 这段时间一直在研究如何提高流表空间的利用率.一直没能想到好的idea.有一篇文献中比较了现有研究中提到的手段,在这里记录一下都有哪些类型的手段以及这些手段存在的不足.这些手段不仅局限于如何提 ...