【算法】树链剖分+线段树

【题解】

树链剖分算法: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]染色的更多相关文章

  1. BZOJ 2243: [SDOI2011]染色 [树链剖分]

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6651  Solved: 2432[Submit][Status ...

  2. bzoj 2243 [SDOI2011]染色(树链剖分,线段树)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4637  Solved: 1726[Submit][Status ...

  3. Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5020  Solved: 1872[Submit][Status ...

  4. bzoj 2243: [SDOI2011]染色 线段树区间合并+树链剖分

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 7925  Solved: 2975[Submit][Status ...

  5. bzoj 2243: [SDOI2011]染色 (树链剖分+线段树 区间合并)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9854  Solved: 3725[Submit][Status ...

  6. BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

  7. BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并

    2243: [SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数 ...

  8. bzoj 2243 [SDOI2011]染色(树链剖分+线段树合并)

    [bzoj2243][SDOI2011]染色 2017年10月20日 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询 ...

  9. 洛谷 P2486 [SDOI2011]染色/bzoj 2243: [SDOI2011]染色 解题报告

    [SDOI2011]染色 题目描述 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同 ...

  10. BZOJ 2243 [SDOI2011]染色 (树链剖分)(线段树区间修改)

    [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6870  Solved: 2546[Submit][Status][Disc ...

随机推荐

  1. 栈和队列在python中的实现

    栈和队列是两种基本的数据结构,同为容器类型.两者根本的区别在于: stack:后进先出 queue:先进先出 PS:stack和queue是不能通过查询具体某一个位置的元素而进行操作的.但是他们的排列 ...

  2. 人生的第一篇blog

    开始写博客了,人生第一篇博客啊,要写些什么呢?想想也没有什么头绪,随便写写吧. 这学期要使用代码管理工具了,要写团队项目了.一直以来都是自己一个人在默默编程,没有过合作经历.对于代码的管理也只是一直在 ...

  3. mnist测试

    第一步:进入caffe目录 第二步:获取mnist数据集 ./data/mnist/get_mnist.sh 第三步:创建lmdb ./examples/mnist/create_mnist.sh 第 ...

  4. Qt使用QNetworkAccessManager实现Ftp操作

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt使用QNetworkAccessManager实现Ftp操作     本文地址:http: ...

  5. 移植spdylay到libcurl

    Libcurl是第三方网络库,支持各种网络协议 SPDY是Google提出的用来替代HTTP1.1的网络协议, 目前google.com, facebook.com, twitter.com服务器端都 ...

  6. web三大组件的加载顺序

    Web三大组件:过滤器组件  监听器组件  Servlet组件 过滤器的顶级接口:javax.servlet.Filter 监听器的顶级接口:javax.servlet.ServletContextL ...

  7. 【数据库】Mysql更改默认引擎为Innodb的步骤方法

    前言 InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定. 基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持.M ...

  8. 最大流Dinic算法模板(pascal)

    program rrr(input,output); const inf=; type pointer=^nodetype; nodetype=record t,c:longint; next,rev ...

  9. ADM pro破解百度云限速 ADM pro设置方法 ES文件管理器

    ADM Pro打开ADM,[设置]–>[下载]–>[找下面的选项]:1.[User-Agent] –>选择[Custom]2.[Custom User-Agent]3.填写:netd ...

  10. javascript的解析顺序

    一.javascript的解析顺序 我们大家所理解的代码的执行顺序都是从上到下的,但是实际上确不是这样的.我们看一下下面的代码. 1 alert(a);2 var a = 1;如果执行顺序是从上到下的 ...