【SDOI2011】染色——树剖的练手题

题目:luogu2486.

题目大意:在一棵树上,支持以下操作:

1.格式C u v x,表示将点u到点v的路径上的点都染成颜色x.

2.格式 Q u v,表示查询点u到点v的路径上相同颜色块的数量.

这道题就是树剖板子题,难点在于如何维护线段树.

线段树其实也不是很难,只需要每个节点维护左端点颜色,右端点颜色,以及颜色块数量就可以了.

但是有一个小问题,树剖的询问,也就是寻找每一条重链的答案该如何合并.

我们直接多定义两个树uc,vc表示u,v当前链的顶端的颜色,交换的时候顺便把这uc,vc交换就可以了.

然后就是很裸的树剖了.

等等树剖的板子怎么敲...

注意一个坑点:初始颜色可以为0.

代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
struct side{ 
  int y,next;
}e[N*2+5];
struct node{
  int dad,son,deep,v,dfn,top,size; 
}nod[N+5];
struct tree{
  int l,r,lc,rc,sum,tag;
}tr[N*5];
int order[N+5],lin[N+5],n,m,t,top;
void ins(int X,int Y){
  e[++top].y=Y;
  e[top].next=lin[X];
  lin[X]=top;
}
int dfs1(int k,int father){
  nod[k].dad=father;
  nod[k].deep=nod[father].deep+1;
  nod[k].size=1;
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^father){
      dfs1(e[i].y,k);
      nod[k].size+=nod[e[i].y].size;
      if (nod[nod[k].son].size<nod[e[i].y].size) nod[k].son=e[i].y;
    }
}
void dfs2(int k,int start){
  nod[k].dfn=++t;
  order[t]=k;
  nod[k].top=start;
  if (nod[k].son) dfs2(nod[k].son,start);
  for (int i=lin[k];i;i=e[i].next)
    if (e[i].y^nod[k].dad&&e[i].y^nod[k].son) dfs2(e[i].y,e[i].y);
}
void pushup(int k){
  int ls=k<<1,rs=k<<1|1;
  tr[k].lc=tr[ls].lc;tr[k].rc=tr[rs].rc;
  tr[k].sum=tr[ls].sum+tr[rs].sum;
  if (tr[ls].rc==tr[rs].lc) tr[k].sum--;
}
void pushdown(int k){
  if (tr[k].tag^-1){
    int ls=k<<1,rs=k<<1|1;
    tr[ls].lc=tr[ls].rc=tr[rs].lc=tr[rs].rc=tr[k].tag;
    tr[ls].sum=tr[rs].sum=1;
    tr[ls].tag=tr[rs].tag=tr[k].tag;
    tr[k].tag=-1;
  }
}
void build(int L,int R,int k=1){
  tr[k].l=L;tr[k].r=R;tr[k].tag=-1;
  if (L==R){
    tr[k].lc=tr[k].rc=nod[order[L]].v;
    tr[k].sum=1;
    return;
  }
  int mid=L+R>>1;
  build(L,mid,k<<1);build(mid+1,R,k<<1|1);
  pushup(k);
}
void change(int L,int R,int v,int k=1){
  if (tr[k].l==L&&tr[k].r==R){
    tr[k].tag=v;
    tr[k].lc=tr[k].rc=v;
    tr[k].sum=1;
    return;
  }
  pushdown(k);
  int mid=tr[k].l+tr[k].r>>1;
  if (R<=mid) change(L,R,v,k<<1);
  else if (L>mid) change(L,R,v,k<<1|1);
    else change(L,mid,v,k<<1),change(mid+1,R,v,k<<1|1);
  pushup(k);
}
struct tree1{
  int lc,rc,sum;
};
tree1 query(int L,int R,int k=1){
  if (tr[k].l==L&&tr[k].r==R) return (tree1){tr[k].lc,tr[k].rc,tr[k].sum};
  int mid=tr[k].l+tr[k].r>>1;
  pushdown(k);
  if (R<=mid) return query(L,R,k<<1);
  else if (L>mid) return query(L,R,k<<1|1);
    else {
      tree1 u=query(L,mid,k<<1),v=query(mid+1,R,k<<1|1),o;
      o.lc=u.lc;o.rc=v.rc;
      o.sum=u.sum+v.sum;
      if (u.rc==v.lc) o.sum--;
      return o;
    }
}
void Change(int u,int v,int c){
  while (nod[u].top^nod[v].top){
    if (nod[nod[u].top].deep<nod[nod[v].top].deep) swap(u,v);
    change(nod[nod[u].top].dfn,nod[u].dfn,c);
    u=nod[nod[u].top].dad;
  }
  if (nod[u].deep>nod[v].deep) swap(u,v);
  change(nod[u].dfn,nod[v].dfn,c);
}
int Query(int u,int v){
  tree1 o;
  int uc=-1,vc=-1,sum=0;
  while (nod[u].top^nod[v].top){
    if (nod[nod[u].top].deep<nod[nod[v].top].deep) swap(u,v),swap(uc,vc);
    o=query(nod[nod[u].top].dfn,nod[u].dfn);
    sum+=o.sum;
    if (uc==o.rc) sum--;
    uc=o.lc;
    u=nod[nod[u].top].dad;
  }
  if (nod[u].deep>nod[v].deep) swap(u,v),swap(uc,vc);
  o=query(nod[u].dfn,nod[v].dfn);
  sum+=o.sum;
  if (o.lc==uc) sum--;
  if (o.rc==vc) sum--;
  return sum;
}
char rc(){
  char c=getchar();
  for (;c<'A'||c>'Z';c=getchar());
  return c; 
}
int ri(){
  int x=0,y=1;
  char c=getchar();
  for (;c<'0'||c>'9';c=getchar()) if (c=='-') y=-1;
  for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
  return x*y;
}
Abigail into(){
  n=ri();m=ri();
  for (int i=1;i<=n;i++)
    nod[i].v=ri();
  int x,y;
  for (int i=1;i<n;i++){
    x=ri();y=ri();
    ins(x,y);ins(y,x);
  }
}
Abigail work(){
  dfs1(1,0);
  dfs2(1,1);
  build(1,n);
  char opt;
  int u,v,c;
  for (int i=1;i<=m;i++){
    opt=rc();
    if (opt=='C'){
      u=ri();v=ri();c=ri();
      Change(u,v,c);
    }else{
      u=ri();v=ri();
      printf("%d\n",Query(u,v));
    }
  }
}
Abigail outo(){
}
int main(){
  into();
  work();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/80954885