【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 ...
随机推荐
- lintocde-247-线段树的查询 II
247-线段树的查询 II 对于一个数组,我们可以对其建立一棵 线段树, 每个结点存储一个额外的值 count 来代表这个结点所指代的数组区间内的元素个数. (数组中并不一定每个位置上都有元素) 实现 ...
- erlang中检查内存泄露
最近项目内存占用过多,检查一下erlang的内存使用情况. 1. 通过etop可以很方便得出erlang内存使用的情况 spawn(fun() -> etop:start([{output, t ...
- FreeMarker(XML模板)导出word
在项目中使用它完成的功能是按照固定的模板将数据导出到Word.比如台账.在完成后将处理过程按照台账的要求导出,有时程序中需要实现生成标准Word文档,要求能够打印,并且保持页面样式不变. 这个功能就是 ...
- utuntu下安装pip&pip3
在utuntu下建议不要使用apt-get install 安装pip,会出现很多问题. 建议使用如下方式安装: wget https://bootstrap.pypa.io/get-pip.py - ...
- USB硬件接口相关
1.USB 设备端的D+为何要拉一个1.5K电阻到3.3v上?(USB是5v供电,但通信的电平是3.3v,所以上拉电平为3.3v:若要上拉到5v,则上拉电阻为10k) usb有主从设备之分,主设备有: ...
- poj2914-Minimum Cut
题意 \(n\) 个点 \(m\) 条边的无向带权图求全局最小割.\(n\le 500,m\le \frac{n(n-1)}{2}\) . 分析 参考了 这篇博客,去给他点赞. 嘛,今天研究了一下全局 ...
- ICPCCamp 2017 I Coprime Queries
给出一个长度为\(n\)的正整数序列\(a\),\(m\)次询问\(l,r,x\),问\(max\{i|i\in[l,r],gcd(a_i,x)=1\}\). \(n,m,a_i\le 10^5\). ...
- MySQL join 使用方法
JOIN 按照功能大致分为如下三类: INNER JOIN(内连接,或等值连接):取得两个表中存在连接匹配关系的记录. LEFT JOIN(左连接):取得左表(table1)完全记录,即是右表(tab ...
- 快速傅里叶变换FFT / NTT
目录 FFT 系数表示法 点值表示法 复数 DFT(离散傅里叶变换) 单位根的性质 FFT(快速傅里叶变换) IFFT(快速傅里叶逆变换) NTT 阶 原根 扩展知识 FFT 参考blog: 十分简明 ...
- CF17E Palisection manacher
题面:洛谷(带翻译) 题解: 直接求相交不太好求,所以考虑求不相交的回文串对数. 设ll[i]表示以i为开头的回文串个数,rr[i]表示结尾<=i的回文串个数. 然后不相交的回文串对数显然就是对 ...