BZOJ2243: [SDOI2011]染色

2243: [SDOI2011]染色

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 8402  Solved: 3151
[Submit][Status][Discuss]

Description

给定一棵有n个节点的无根树和m个操作,操作有2类:

1、将节点a到节点b路径上所有点都染成颜色c

2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。

请你写一个程序依次完成这m个操作。

Input

第一行包含2个整数nm,分别表示节点数和操作数;

第二行包含n个正整数表示n个节点的初始颜色

下面行每行包含两个整数xy,表示xy之间有一条无向边。

下面行每行描述一个操作:

“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括ab)都染成颜色c

“Q a b”表示这是一个询问操作,询问节点a到节点b(包括ab)路径上的颜色段数量。

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

HINT

数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。

思路{

  颜色段发现用树链剖分的时候记录一下区间左右端点,比较一下就可以了.

  有点码.....

}

#include<bits/stdc++.h>
#define il inline
#define RG register
#define ll long long
#define db double
#define N 100010
using namespace std;
int w[N];
struct ed{int nxt,to;}e[N*2];
int head[N],tot,n,m;
void LINK(int u,int v){e[tot].nxt=head[u];e[tot].to=v;head[u]=tot++;}
void link(int u,int v){LINK(u,v),LINK(v,u);}
namespace Tree{
#define ls (o<<1)
#define rs ((o<<1)|1)
#define mid ((l+r)>>1)
  int id[N],top[N],deep[N],idw[N],fa[N],sz[N],hson[N],idn;
  int Sum[N*4],lc[N*4],rc[N*4],lazy[N*4];
  void dfs1(int u,int faa){
    deep[u]=deep[faa]+1;fa[u]=faa;sz[u]=1;
    for(int i=head[u];i!=-1;i=e[i].nxt)if(e[i].to!=faa){
    int v=e[i].to;dfs1(v,u);
    sz[u]+=sz[v];if(sz[v]>sz[hson[u]])hson[u]=v;
      }
  }
  void dfs2(int u,int toop){
    id[u]=++idn;idw[idn]=w[u];top[u]=toop;
    if(hson[u])dfs2(hson[u],toop);
    for(int i=head[u];i!=-1;i=e[i].nxt)
      if(e[i].to!=hson[u]&&e[i].to!=fa[u])
    dfs2(e[i].to,e[i].to);
  }
  void up(int o){
    Sum[o]=Sum[ls]+Sum[rs];
    if(rc[ls]==lc[rs])Sum[o]--;
    rc[o]=rc[rs],lc[o]=lc[ls];
  }
  void build(int o,int l,int r){
    if(l==r){Sum[o]=1,rc[o]=lc[o]=idw[l];return;}
    build(rs,mid+1,r),build(ls,l,mid);
    up(o);
  }
  void down(int o){
    if(lazy[o]){
      Sum[rs]=Sum[ls]=1;
      rc[rs]=lc[rs]=lazy[rs]=lazy[o];
      rc[ls]=lc[ls]=lazy[ls]=lazy[o];
      lazy[o]=0;
    }
  }
  void Modify(int o,int l,int r,int L,int R,int c){
    if(l!=r)down(o);
    if(l>=L&&r<=R){
      Sum[o]=1;
      rc[o]=lc[o]=lazy[o]=c;
      return;
    }
    if(mid<L)Modify(rs,mid+1,r,L,R,c);
    else if(mid>=R)Modify(ls,l,mid,L,R,c);
    else Modify(rs,mid+1,r,mid,R,c),Modify(ls,l,mid,L,mid,c);
    up(o);
  }
  int Query(int o,int l,int r,int L,int R){
    if(l!=r)down(o);
    if(l>=L&&r<=R)return Sum[o];
    if(mid<L)return Query(rs,mid+1,r,L,R);
    if(mid>=R)return Query(ls,l,mid,L,R);
    else return Query(rs,mid+1,r,L,R)+Query(ls,l,mid,L,R)-(rc[ls]==lc[rs]);
  }
  int Querycol(int o,int l,int r,int pos){
    if(l!=r)down(o);if(l==r)return rc[o];
    if(mid<pos)return Querycol(rs,mid+1,r,pos);
    else return Querycol(ls,l,mid,pos);
  }
  void work1(int x,int y,int c){
    while(top[x]!=top[y]){
      if(deep[top[x]]<deep[top[y]])swap(x,y);
      Modify(1,1,n,id[top[x]],id[x],c);
      x=fa[top[x]];
    }
    if(deep[x]>deep[y])swap(x,y);
    Modify(1,1,n,id[x],id[y],c);
  }
  void work2(int x,int y){
    ll sum(0);
    while(top[x]!=top[y]){
      if(deep[top[x]]<deep[top[y]])swap(x,y);
      sum+=Query(1,1,n,id[top[x]],id[x]);
      if(Querycol(1,1,n,id[top[x]])==Querycol(1,1,n,id[fa[top[x]]]))sum--;
      x=fa[top[x]];
    }
    if(deep[x]>deep[y])swap(x,y);
    sum+=Query(1,1,n,id[x],id[y]);
    cout<<sum<<"\n";
  }
}
char C[2];
int main(){
  memset(head,-1,sizeof(head));
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;++i)scanf("%d",&w[i]);
  for(int i=1;i<n;++i){int u,v;scanf("%d%d",&u,&v),link(u,v);}
  Tree::dfs1(1,1),Tree::dfs2(1,1);Tree::build(1,1,n);
  for(int i=1;i<=m;++i){
    scanf("%s",C);
    if(C[0]=='C'){
      int a,b,c;scanf("%d%d%d",&a,&b,&c);
      Tree::work1(a,b,c);
    }
    else {
      int a,b;scanf("%d%d",&a,&b);
      Tree::work2(a,b);
    }
  }
  return 0;
}

 

posted @ 2017-09-13 00:10  QYP_2002  阅读(174)  评论(0编辑  收藏  举报