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

【题解】

树链剖分算法: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. MDL数据结构

    微软的文档里对MDL的描述感觉语焉不详,这两天在找工作的间隙逆向+黑盒测试了一下MmBuildMdlForNonPagedPool,把得到的一些理解描述下来. 一.MDL数据结构 MDL是用来建立一块 ...

  2. OSG学习:使用OSG中预定义的几何体

    常用的内嵌几何体包括: osg::Box //正方体 osg::Capsule //太空舱 osg::Cone //椎体 osg::Cylinder //柱体 osg::HeightField //高 ...

  3. 【第五周】四则运算GUI

    这次这个简陋的程序终于发布了,其实发布很简单(在windows平台),因为使用的是vs2008+qt4.7的组合,在微软自家平台上用一用还是很方便的,只需要在release编译生成的exe文件,加上几 ...

  4. Python入门:认识变量和字符串

    几个月前,我开始学习个人形象管理,从发型.妆容.服饰到仪表仪态,都开始做全新改造,在塑造个人风格时,最基础的是先了解自己属于哪种风格,然后找到参考对象去模仿,可以是自己欣赏的人.明星或模特等,直至最后 ...

  5. 7. 由一道ctf学习变量覆盖漏洞

    0×00 背景 近期在研究学习变量覆盖漏洞的问题,于是就把之前学习的和近期看到的CTF题目中有关变量覆盖的题目结合下进一步研究. 通常将可以用自定义的参数值替换原有变量值的情况称为变量覆盖漏洞.经常导 ...

  6. Android应用流量测试

    工具 GT(中文产品名称:随身调):是腾讯出品的开源调试工具,本次测试中用其进行手机的流量统计和抓包.请在Android手机上安装GT应用(可以通过官网或应用宝下载). Wireshark:抓包的分析 ...

  7. HttpWebRequest 保存Cookies,模拟Session登录

    前面使用HttpWebRequest 对象可以抓取网页中一些资料,不过有些页面可以直接打开,而有些页面必登录之后才能打开,也就是在登录后保存登录信息在Session,这样就可以访问有权限的页面了.下面 ...

  8. P2323 [HNOI2006]公路修建问题

    题目描述 输入输出格式 输入格式: 在实际评测时,将只会有m-1行公路 输出格式: 输入输出样例 输入样例#1: 4 2 5 1 2 6 5 1 3 3 1 2 3 9 4 2 4 6 1 输出样例# ...

  9. Django安装及简介

    一. Django简介 Python下有许多款不同的 Web 框架.Django是重量级选手中最有代表性的一位.许多成功的网站和APP都基于Django. Django是一个开放源代码的Web应用框架 ...

  10. 【CF528D】Fuzzy Search(FFT)

    [CF528D]Fuzzy Search(FFT) 题面 给定两个只含有\(A,T,G,C\)的\(DNA\)序列 定义一个字符\(c\)可以被匹配为:它对齐的字符,在距离\(K\)以内,存在一个字符 ...