题意:
给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
思路:
这道题敲了很久…..(好恶心….
但是AC了真的很exciting
就是要考虑到区间合并,两条链进行合并的时候要判断
ft[x][i]就是从x节点向上跳2^i次方个节点所到达的节点
就是运用倍增的思想…倍增思想的请看郭大侠的讲解http://www.bilibili.com/video/av4419432/
这道题有两个操作
1、将节点a到节点b路径上所有点都染成颜色c 这个很简单,就是正常的树剖+线段树+lazy就OK了
还有LCA有点麻烦
下一个
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。这里需要+区间合并
我们先剖分整棵树,注意再剖分的过程中进行倍增的预处理,因为我们要求LCA
然后线段树query拆分区间的时候要注意一下
每次查询和插入的时候我们通过把区间分为[L,LCA] and [LCA,R]来处理
这么想想….好像是水题QAQ
就是区间合并和求LCA的时候注意一下就行了
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x&(-x))
typedef long long LL;
#define maxn 200005
const int inf=(1<<28)-1;
int A[maxn];
struct node
{
int next,to;
}e[maxn*2];
int h[maxn],tot;
void add_edge(int a,int b)
{
e[++tot].next=h[a];
e[tot].to=b;
h[a]=tot;
}
//Graph*******************************
int ft[maxn][18];
int son[maxn],fa[maxn],siz[maxn],deep[maxn];
//求重儿子 父亲节点 节点子树大小 深度 和倍增节点
void dfs1(int u,int pre,int dep)
{
deep[u]=dep;fa[u]=pre;
siz[u]=1;
for(int i=1;i<=17;++i)
{
if(deep[u]<(1<<i)) break;
ft[u][i]=ft[ft[u][i-1]][i-1];
}
for(int i=h[u];~i;i=e[i].next)
{
int v=e[i].to;
if(v!=pre)
{
ft[v][0]=u;
dfs1(v,u,dep+1);
siz[u]+=siz[v];
if(son[u]==-1||siz[son[u]]<siz[v])
son[u]=v;
}
}
}
int tid[maxn],Rank[maxn],top[maxn];
int tim;
//给节点标号和求top节点
void dfs2(int u,int tp)
{
top[u]=tp;
tid[u]=++tim;
Rank[tim]=u;
if(son[u]==-1) return ;
dfs2(son[u],tp);
for(int i=h[u];~i;i=e[i].next)
{
int v=e[i].to;
if(v!=fa[u]&&v!=son[u])
dfs2(v,v);
}
}
int lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
int t=deep[x]-deep[y];
for(int i=0;i<18;++i)
if(t&(1<<i)) x=ft[x][i];
for(int i=17;i>=0;--i)
if(ft[x][i]!=ft[y][i])
{
x=ft[x][i];
y=ft[y][i];
}
if(x==y) return x;
return ft[x][0];
}
//树剖*********************************
struct Segment
{
int lc,rc,sum,lazy;
}tree[maxn*4];
void Push_up(int rt)
{
tree[rt].lc=tree[rt*2].lc;
tree[rt].rc=tree[rt*2+1].rc;
tree[rt].sum=tree[rt*2].sum+tree[rt*2+1].sum;
if(tree[rt*2].rc==tree[rt*2+1].lc)
tree[rt].sum--;
}
void Copy(int rt1,int rt)
{
tree[rt1].lc=tree[rt].lazy;
tree[rt1].rc=tree[rt].lazy;
tree[rt1].lazy=tree[rt].lazy;
tree[rt1].sum=1;
}
void Push_down(int rt)
{
if(tree[rt].lazy==-1) return ;
Copy(rt*2,rt);
Copy(rt*2+1,rt);
tree[rt].lazy=-1;
}
void build(int l,int r,int rt)
{
tree[rt].lazy=-1;
if(l==r)
{
tree[rt].lc=tree[rt].rc=A[Rank[l]];
tree[rt].sum=1;
return ;
}
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
Push_up(rt);
}
void Insert(int left,int right,int l,int r,int rt,int c)
{
if(left<=l&&r<=right)
{
tree[rt].lc=tree[rt].rc=c;
tree[rt].sum=1;tree[rt].lazy=c;
return ;
}
Push_down(rt);
int mid=(l+r)/2;
if(left<=mid)
Insert(left,right,l,mid,rt*2,c);
if(right>mid)
Insert(left,right,mid+1,r,rt*2+1,c);
Push_up(rt);
}
int query(int left,int right,int l,int r,int rt)
{
if(left<=l&&r<=right) return tree[rt].sum;
Push_down(rt);
int mid=(l+r)/2;
int tmp=0;
if(left>mid)
tmp=query(left,right,mid+1,r,rt*2+1);
else if(right<=mid)
tmp=query(left,right,l,mid,rt*2);
else
{
tmp=query(left,right,l,mid,rt*2);
tmp+=query(left,right,mid+1,r,rt*2+1);
if(tree[rt*2].rc==tree[rt*2+1].lc) tmp--;
}
Push_up(rt);
return tmp;
}
int find(int pos,int l,int r,int rt)
{
if(l==r) return tree[rt].lc;
Push_down(rt);
int mid=(l+r)/2,tmp;
if(pos>mid) return find(pos,mid+1,r,rt*2+1);
else return find(pos,l,mid,rt*2);
Push_up(rt);
return tmp;
}
//Segment*********************************
void init()
{
tot=0,tim=0;
memset(h,-1,sizeof(h));
memset(son,-1,sizeof(son));
}
int n;
void Change(int x,int t,int c)
{
while(top[x]!=top[t])
{
Insert(tid[top[x]],tid[x],1,n,1,c);
x=fa[top[x]];
}
Insert(tid[t],tid[x],1,n,1,c);
}
int Solve(int x,int t)
{
int res=0;
while(top[x]!=top[t])
{
res+=query(tid[top[x]],tid[x],1,n,1);
if(find(tid[top[x]],1,n,1)==find(tid[ft[top[x]][0]],1,n,1)) res--;
x=fa[top[x]];
}
res+=query(tid[t],tid[x],1,n,1);
return res;
}
int main()
{
init();
int m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&A[i]);
for(int i=1;i<n;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
dfs1(1,0,0);
dfs2(1,1);
build(1,n,1);
for(int i=1;i<=m;++i)
{
char str[5];
scanf("%s",str);
if(str[0]=='C')
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
int t=lca(u,v);
Change(u,t,c);
Change(v,t,c);
}
else
{
int u,v;
scanf("%d%d",&u,&v);
int t=lca(u,v);
printf("%d\n",Solve(u,t)+Solve(v,t)-1);
}
}
return 0;
}