2243: [SDOI2011]染色
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5001 Solved: 1860
[ Submit][ Status][ Discuss]
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
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
1
2
HINT
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
Source
首先对树轻重链剖分,维护线段树一段的颜色,最左边和最右边的颜色即可。
#include "iostream"
#include "stdio.h"
using namespace std;
inline void read(int &v){
char ch=getchar();v=0;
while(ch>'9'||ch<'0')ch=getchar();
do{v=v*10+ch-'0',ch=getchar();}
while(ch<='9'&&ch>='0');
}
const int N=100005,oo=0x7fffffff,G=17;
int n,m,color[N],push[N],size[N],deep[N];
int head[N],next[2*N],route[2*N],fa[N][G+1];
int pos[N],belong[N],tmp;
inline void add_arc(int x,int y,int i){
next[i]=head[x];
route[i]=y;
head[x]=i;
}//O(1)
inline int lca(int u,int v){
if(deep[u]<deep[v]) swap(u,v);
int len=deep[u]-deep[v],i;
for (i=G;i>=0;i--)
if(len&(1<<i))
u=fa[u][i];
for (i=G;i>=0;i--)
if(fa[u][i]!=fa[v][i])
u=fa[u][i],v=fa[v][i];
if(u==v) return u;
return fa[u][0];
}//O(log n)
int dfs1(int v){int k;size[v]=1;
for (k=1;(1<<k)<=deep[v];k++){
fa[v][k]=fa[fa[v][k-1]][k-1];
}
for (k=head[v];k;k=next[k]){
if(deep[route[k]]>deep[v])
{deep[route[k]]=deep[v]+1;
fa[route[k]][0]=v;dfs1(route[k]);
size[v]+=size[route[k]];}
}
return size[v];
}//O(n)
void dfs2(int v,int bel){
int k,u=0; belong[v]=bel;
pos[v]=++tmp; push[tmp]=color[v];
for (k=head[v];k;k=next[k])
if(size[u]<size[route[k]]&&deep[route[k]]>deep[v])
u=route[k];
if(!u)return;
dfs2(u,bel);
for (k=head[v];k;k=next[k])
if(route[k]!=u&&deep[route[k]]>deep[v])
dfs2(route[k],route[k]);
}//O(n)
void build(){int i,u,v;
for (i=1;i<n;i++){
read(u),read(v);
add_arc(u,v,2*i-1);
add_arc(v,u,2*i);
}deep[1]=0;
dfs1(1),dfs2(1,1);
}//O(n)
struct SegMent{
int l,r,color;
int lco,rco;
int ans;
} seg[N<<2];
inline void Build(int l,int r,int v){int mid=(l+r)>>1;
seg[v].l=l,seg[v].r=r;seg[v].color=0;
if(l==r){seg[v].color=seg[v].lco=seg[v].rco=push[l]+1;
seg[v].ans=1; return ;}Build(l,mid,v<<1),Build(mid+1,r,v<<1|1);
seg[v].lco=seg[v<<1].lco,seg[v].rco=seg[v<<1|1].rco;
seg[v].ans=seg[v<<1].ans+seg[v<<1|1].ans-(seg[v<<1].rco==seg[v<<1|1].lco);
}//O(n)
inline void paint(int l,int r,int c,int v){
int mid=(seg[v].l+seg[v].r)>>1;
if(seg[v].l==l&&seg[v].r==r)
{ seg[v].color=seg[v].lco=seg[v].rco=c;
seg[v].ans=1; return ;}
if(seg[v].color==c) return;
if(seg[v].color)
{ seg[v<<1].color=seg[v<<1|1].color=seg[v<<1].lco=
seg[v<<1].rco=seg[v<<1|1].lco=seg[v<<1|1].rco=seg[v].color;
seg[v<<1].ans=seg[v<<1|1].ans=1;
seg[v].color=0;
}
if(r<=mid) paint(l,r,c,v<<1);
else if(l>mid) paint(l,r,c,v<<1|1);
else paint(l,mid,c,v<<1),paint(mid+1,r,c,v<<1|1);
seg[v].lco=seg[v<<1].lco,seg[v].rco=seg[v<<1|1].rco;
seg[v].ans=seg[v<<1].ans+seg[v<<1|1].ans-(seg[v<<1].rco==seg[v<<1|1].lco);
}//O(log n)
inline int count(int v,int l,int r,int last,int &ans){
int mid=(seg[v].l+seg[v].r)>>1;
if(seg[v].l==l&&seg[v].r==r)
{ ans+=seg[v].ans-(last==seg[v].rco); return seg[v].lco; }
if(seg[v].color)
{ ans+=last!=seg[v].rco; return seg[v].color;
}
if(r<=mid) return count(v<<1,l,r,last,ans);
else if(l>mid) return count(v<<1|1,l,r,last,ans);
return count(v<<1,l,mid,count(v<<1|1,mid+1,r,last,ans),ans);
}//O(log n)
inline void Color(int u,int v,int co){
int t=lca(u,v);swap(v,t);
while (belong[u]!=belong[v]){
paint(pos[belong[u]],pos[u],co,1);
u=fa[belong[u]][0];
}
paint(pos[v],pos[u],co,1);swap(u,t);
while (belong[u]!=belong[v]){
paint(pos[belong[u]],pos[u],co,1);
u=fa[belong[u]][0];
}
paint(pos[v],pos[u],co,1);
}//O(log n^2)
inline int Query(int u,int v){
int t=lca(u,v);swap(v,t);
int ans=0,last=-1;
while (belong[u]!=belong[v]){
last=count(1,pos[belong[u]],pos[u],last,ans);
u=fa[belong[u]][0];
}
count(1,pos[v],pos[u],last,ans);swap(u,t);last=-1;
while (belong[u]!=belong[v]){
last=count(1,pos[belong[u]],pos[u],last,ans);
u=fa[belong[u]][0];
}
last=count(1,pos[v],pos[u],last,ans);
return ans-1;
}//O(log n^2)
void work(){
for (int i=0;i<m;i++){
char ch=getchar();int u,v,c;
while(ch!='Q'&&ch!='C')ch=getchar();
read(u),read(v);
if(ch=='C') read(c),Color(u,v,c+1);
else printf("%d\n",Query(u,v));
}
}//O(m log n^2 + n)
int main(){
// freopen("paint.in","r",stdin);
// freopen("paint.out","w",stdout);
read(n),read(m);
for(int i=1;i<=n;i++)
read(color[i]),deep[i]=oo;
build(),Build(1,n,1),work();
return 0;
}//O(m log n^2 + n)
标复杂度是因为我一开始写TLE了……到最后才发现在LCA那出了一点小问题……