BZOJ 2243 染色(树链剖分+线段树)
2015-12-06 10:53
423 查看
Description
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
Input
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
Output
对于每个询问操作,输出一行答案。
Sample Input
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
Sample Output
3
1
2
Solution
树上路径问题,首先树链剖分,然后线段树中元素lc和rc表示区间左右端点的颜色,num表示区间颜色段数量,flag表示是否被覆盖(如果被覆盖flag记录被覆盖的颜色),每次C a b c操作就是区间更新[a,lca(a,b)]和[b,lca(a,b)],Q a b就是区间查询[a,lca(a,b)]和[b,lca(a,b)]的颜色段数量然后减一( lca(a,b)被算了两遍),注意每次区间合并时需要判断左区间的rc和右区间的lc是否相同,如果相同那么总区间的颜色段数量等于左右区间颜色段数量之和减一
Code
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
Input
第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。
Output
对于每个询问操作,输出一行答案。
Sample Input
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
Sample Output
3
1
2
Solution
树上路径问题,首先树链剖分,然后线段树中元素lc和rc表示区间左右端点的颜色,num表示区间颜色段数量,flag表示是否被覆盖(如果被覆盖flag记录被覆盖的颜色),每次C a b c操作就是区间更新[a,lca(a,b)]和[b,lca(a,b)],Q a b就是区间查询[a,lca(a,b)]和[b,lca(a,b)]的颜色段数量然后减一( lca(a,b)被算了两遍),注意每次区间合并时需要判断左区间的rc和右区间的lc是否相同,如果相同那么总区间的颜色段数量等于左右区间颜色段数量之和减一
Code
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; #define maxn 111111 struct Edge { int to,next; }E[2*maxn]; struct Tree { int left,right,lc,rc,num,flag; }T[4*maxn]; //lc,rc记录区间端点即left和right的颜色 //num记录区间[left,right]中颜色段数量 //flag记录区间是否被某种颜色全覆盖 int n,q,c[maxn],head[maxn],cnt,idx,size[maxn],fa[maxn],son[maxn],dep[maxn],top[maxn],id[maxn]; void init() { cnt=idx=0; memset(head,-1,sizeof(head)); dep[1]=fa[1]=size[0]=0; memset(son,0,sizeof(son)); } void add(int u,int v) { E[cnt].to=v; E[cnt].next=head[u]; head[u]=cnt++; } void dfs1(int u) { size[u]=1; for(int i=head[u];~i;i=E[i].next) { int v=E[i].to; if(v!=fa[u]) { fa[v]=u; dep[v]=dep[u]+1; dfs1(v); size[u]+=size[v]; if(size[son[u]]<size[v]) son[u]=v; } } } void dfs2(int u,int topu) { top[u]=topu; id[u]=++idx; if(son[u]) dfs2(son[u],top[u]); for(int i=head[u];~i;i=E[i].next) { int v=E[i].to; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } } void push_up(int t) { T[t].lc=T[2*t].lc; T[t].rc=T[2*t+1].rc; T[t].num=T[2*t].num+T[2*t+1].num; if(T[2*t].rc==T[2*t+1].lc) T[t].num--;//左区间右端点颜色等于右区间左端点颜色时总颜色段数量减一 } void push_down(int t) { if(T[t].left==T[t].right||T[t].flag==-1) { T[t].flag=-1; return ; } T[2*t].lc=T[2*t].rc=T[2*t+1].lc=T[2*t+1].rc=T[t].flag; T[2*t].flag=T[2*t+1].flag=T[t].flag; T[2*t].num=T[2*t+1].num=1; T[t].flag=-1; } void build(int l,int r,int t)//建树 { T[t].left=l; T[t].right=r; T[t].num=1; T[t].flag=-1; if(l==r) return ; int mid=(l+r)>>1; build(l,mid,2*t); build(mid+1,r,2*t+1); } void update(int l,int r,int z,int t)//区间更新[l,r]的颜色为t { push_down(t); if(T[t].left==l&&T[t].right==r) { T[t].lc=T[t].rc=T[t].flag=z; T[t].num=1; return ; } if(r<=T[2*t].right) update(l,r,z,2*t); else if(l>=T[2*t+1].left) update(l,r,z,2*t+1); else { update(l,T[2*t].right,z,2*t); update(T[2*t+1].left,r,z,2*t+1); } push_up(t); } int modify(int l,int r,int t)//区间查询[l,r]上的颜色段数量 { push_down(t); if(T[t].left==l&&T[t].right==r) return T[t].num; if(r<=T[2*t].right) return modify(l,r,2*t); else if(l>=T[2*t+1].left) return modify(l,r,2*t+1); else { int ans=T[2*t].rc==T[2*t+1].lc;//左区间右端点颜色等于右区间左端点颜色时总颜色段数量减一 return modify(l,T[2*t].right,2*t)+modify(T[2*t+1].left,r,2*t+1)-ans; } } int get_color(int x,int t)//单点查询树上某节点颜色 { if(T[t].left==x&&T[t].right==x) return T[t].lc; push_down(t); if(x<=T[2*t].right) return get_color(x,2*t); return get_color(x,2*t+1); } int lca(int u,int v)//求u节点和v节点的lca { int top1=top[u],top2=top[v]; while(top1!=top2) { if(dep[top1]<dep[top2]) { swap(top1,top2); swap(u,v); } u=fa[top1]; top1=top[u]; } return dep[u]<dep[v]?u:v; } void change(int f,int u,int z)//修改树上f节点到u节点之间的颜色为z { int top1=top[u],top2=top[f]; while(top1!=top2) { update(id[top1],id[u],z,1); u=fa[top1]; top1=top[u]; } update(id[f],id[u],z,1); } int query(int f,int u)//查询树上f节点到u节点之间的颜色段数量 { int top1=top[u],top2=top[f],ans=0; while(top1!=top2) { ans+=modify(id[top1],id[u],1); if(get_color(id[top1],1)==get_color(id[fa[top1]],1)) ans--;//左区间右端点颜色等于右区间左端点颜色时总颜色段数量减一 u=fa[top1]; top1=top[u]; } ans+=modify(id[f],id[u],1); return ans; } int main() { while(~scanf("%d%d",&n,&q)) { init();//初始化 int u,v,color;char op[11]; for(int i=1;i<=n;i++) scanf("%d",&c[i]); for(int i=1;i<n;i++) { scanf("%d%d",&u,&v); add(u,v),add(v,u); } dfs1(1); dfs2(1,1); build(1,n,1);//建树 for(int i=1;i<=n;i++) update(id[i],id[i],c[i],1);//单点更新就是左右端点相同的区间更新 while(q--) { scanf("%s",op); if(op[0]=='C') { scanf("%d%d%d",&u,&v,&color); int x=lca(u,v); change(x,u,color); change(x,v,color); } else { scanf("%d%d",&u,&v); int x=lca(u,v); printf("%d\n",query(x,u)+query(x,v)-1); } } } return 0; }
相关文章推荐
- 用Python和OpenCV创建一个图片搜索引擎的完整指南
- python 数据库连接
- 简单图形xml文件定义
- Apply Newton Method to Find Extrema in OPEN CASCADE
- 1043. Is It a Binary Search Tree (25)
- image lazyload 原理分析
- 游戏化编程网站
- Caffe + Ubuntu 15.04 + CUDA 7.0 安装以及配置
- 基于.net搭建热插拔式web框架(实现原理)
- AAS代码运行-第4章
- 1042. Shuffling Machine (20)
- ubuntu apache linux
- unity3d添加武器功能
- Android如何优雅的缓存网络图片
- POJ-2656
- 20151206
- 跳舞毯
- svnChina的使用方法
- LeetCode 283:Move Zeroes
- Java中的泛型编程(generic programming)和泛型类(generic class)