给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。
请你写一个程序依次完成这m个操作。
第一行包含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)路径上的颜色段数量。
对于每个询问操作,输出一行答案。
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
3
1
2
数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。
第一轮day1
如果是序列的话就是线段树傻X题吧…
改成树上,就剖一下,区间修改+区间查询而已…
#include
#include
#include
#include
using namespace std;
const int size=1000010;
int head[size],nxt[size],to[size],tot=0;
void build(int f,int t)
{
to[++tot]=t;
nxt[tot]=head[f];
head[f]=tot;
}
int fa[size],sz[size],son[size],deep[size];
int inseg[size],top[size];
void dfs_1(int u,int f)
{
deep[u]=deep[f]+1;
sz[u]=1;
fa[u]=f;
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(v==f) continue;
dfs_1(v,u);
sz[u]+=sz[v];
if(!son[u]||sz[v]>sz[son[u]]) son[u]=v;
}
}
int totp=0;
void dfs_2(int u,int topu)
{
top[u]=topu;
inseg[u]=++totp;
if(!son[u]) return;
dfs_2(son[u],topu);
for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(v==fa[u]||v==son[u]) continue;
dfs_2(v,v);
}
}
struct segment{
int l,r;
int ans,lc,rc,c;
}tree[size];
void update(int p)
{
tree[p].lc=tree[p<<1].lc;
tree[p].rc=tree[p<<1|1].rc;
if(tree[p<<1].rc==tree[p<<1|1].lc)
tree[p].ans=tree[p<<1].ans+tree[p<<1|1].ans-1;
else
tree[p].ans=tree[p<<1].ans+tree[p<<1|1].ans;
}
void build_tree(int p,int l,int r)
{
tree[p].l=l; tree[p].r=r;
if(l==r)
{
tree[p].ans=tree[p].lc=tree[p].rc=tree[p].c=0;
return ;
}
int mid=(l+r)>>1;
build_tree(p<<1,l,mid);
build_tree(p<<1|1,mid+1,r);
update(p);
}
void spread(int p)
{
if(tree[p].c)
{
tree[p<<1|1].ans=1;
tree[p<<1|1].lc=tree[p].c;
tree[p<<1|1].rc=tree[p].c;
tree[p<<1|1].c=tree[p].c;
tree[p<<1].ans=1;
tree[p<<1].lc=tree[p].c;
tree[p<<1].rc=tree[p].c;
tree[p<<1].c=tree[p].c;
tree[p].c=0;
}
}
void change(int p,int l,int r,int c)
{
if(l<=tree[p].l&&tree[p].r<=r)
{
tree[p].ans=1;
tree[p].lc=c; tree[p].rc=c;
tree[p].c=c;
return ;
}
spread(p);
int mid=(tree[p].l+tree[p].r)>>1;
if(l<=mid) change(p<<1,l,r,c);
if(mid1|1,l,r,c);
update(p);
}
int ask_ans(int p,int l,int r)
{
if(l<=tree[p].l&&tree[p].r<=r)
{
return tree[p].ans;
}
spread(p);
int mid=(tree[p].l+tree[p].r)>>1;
int ans=0;
if(l<=mid&&midif(tree[p<<1].rc==tree[p<<1|1].lc)
ans+=ask_ans(p<<1,l,mid)+ask_ans(p<<1|1,mid+1,r)-1;
else
ans+=ask_ans(p<<1,l,mid)+ask_ans(p<<1|1,mid+1,r);
}
else if(l<=mid) ans+=ask_ans(p<<1,l,r);
else if(mid1|1,l,r);
return ans;
}
int ask_color(int p,int x)
{
if(tree[p].l==tree[p].r)
{
return tree[p].lc;
}
spread(p);
int mid=(tree[p].l+tree[p].r)>>1;
if(x<=mid) return ask_color(p<<1,x);
else return ask_color(p<<1|1,x);
}
int find_ans(int x,int y)
{
int fx=top[x],fy=top[y];
int ans=0;
while(fx!=fy)
{
if(deep[fx]1,inseg[fx],inseg[x]);
if(ask_color(1,inseg[fx])==ask_color(1,inseg[fa[fx]]))
ans--;
x=fa[fx],fx=top[x];
}
if(deep[x]>deep[y]) swap(x,y);
ans+=ask_ans(1,inseg[x],inseg[y]);
return ans;
}
void find_change(int x,int y,int c)
{
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(deep[fx]1,inseg[fx],inseg[x],c);
x=fa[fx],fx=top[x];
}
if(deep[x]>deep[y]) swap(x,y);
change(1,inseg[x],inseg[y],c);
}
int data[size];
int main()
{
freopen("2243.in","r",stdin);
freopen("2243.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&data[i]);
}
for(int i=1;i<=n-1;i++)
{
int a,b;
scanf("%d%d",&a,&b);
build(a,b); build(b,a);
}
dfs_1(1,0); dfs_2(1,1);
build_tree(1,1,n);
for(int i=1;i<=n;i++)
{
change(1,inseg[i],inseg[i],data[i]);
}
while(m--)
{
char s[5];
scanf("%s",s);
switch(s[0])
{
case 'C':
int l,r,c;
scanf("%d%d%d",&l,&r,&c);
if(inseg[l]>inseg[r]) swap(l,r);
find_change(l,r,c);
break;
case 'Q':
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",find_ans(a,b));
break;
}
}
return 0;
}
/*
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
*/