BZOJ 2243: [SDOI2011]染色(树链剖分)

匿名 (未验证) 提交于 2019-12-03 00:43:02

2243: [SDOI2011] Ⱦɫ

  Time Limit: 20 Sec
  Memory Limit: 512 MB

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 1

  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 1

  3
  1
  2

HINT

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

     
  此题的关键是线段树记录的信息是什么
  线段树上记三个量:
  该段颜色段数,左端点颜色,右端点颜色
  在合并的时候段点颜色要特别小心仔细
  写法技巧和细节也很重要
  其余树链剖分
www.cnblogs.com/AGFghy/


AC代码

#include<cstdio> #include<algorithm> using namespace std; const int N=1e5+5; int n,m,u,v,x,y,c,num,cnt; int point[N<<1],next[N<<1],head[N]; int fa[N],dep[N],size[N],son[N],id[N],top[N]; int a[N],fc[N]; char pd[5]; struct node {     int lc,rc,v,lazy; }tree[N<<2];  void add(int u,int v) {     point[++num]=v;     next[num]=head[u];     head[u]=num; } void dfs1(int now,int pre) {     fa[now]=pre;     dep[now]=dep[pre]+1;     size[now]=1;     for (int i=head[now]; i; i=next[i])     {         int v=point[i];         if (v==pre) continue;         dfs1(v,now);         size[now]+=size[v];         if (size[v]>size[son[now]]) son[now]=v;     } } void dfs2(int now,int topf) {     top[now]=topf;     id[now]=++cnt;     a[cnt]=fc[now]+1;     if (!son[now]) return;     dfs2(son[now],topf);     for (int i=head[now]; i; i=next[i])     {         int v=point[i];         if (v==fa[now] || v==son[now]) continue;         dfs2(v,v);     } } void pushup(int p) {     tree[p].lc=tree[p<<1].lc;     tree[p].rc=tree[(p<<1)+1].rc;     tree[p].v=tree[p<<1].v+tree[(p<<1)+1].v-(tree[p<<1].rc==tree[(p<<1)+1].lc); } void pushdown(int p) {     if (tree[p].lazy)     {         tree[p<<1].lc=tree[p<<1].rc=tree[p<<1].lazy=tree[p].lazy; tree[p<<1].v=1;         tree[(p<<1)+1].lc=tree[(p<<1)+1].rc=tree[(p<<1)+1].lazy=tree[p].lazy; tree[(p<<1)+1].v=1;         tree[p].lazy=0;     } } void build(int l,int r,int p) {     if (l==r)     {         tree[p].lc=tree[p].rc=a[l];         tree[p].v=1;         return;     }     int mid=(l+r)>>1;     build(l,mid,p<<1);     build(mid+1,r,(p<<1)+1);     pushup(p); } void update(int l,int r,int p,int s,int t,int c) {     if (l==s && r==t)     {         tree[p].lc=tree[p].rc=tree[p].lazy=c;         tree[p].v=1;         return;     }     pushdown(p);     int mid=(l+r)>>1;     if (t<=mid) update(l,mid,p<<1,s,t,c);     else if (s>mid) update(mid+1,r,(p<<1)+1,s,t,c);     else     {         update(l,mid,p<<1,s,mid,c);         update(mid+1,r,(p<<1)+1,mid+1,t,c);     }     pushup(p); } node query(int l,int r,int p,int s,int t) {     if (l==s && r==t) return tree[p];     pushdown(p);     int mid=(l+r)>>1;     if (t<=mid) return query(l,mid,p<<1,s,t);     else if (s>mid) return query(mid+1,r,(p<<1)+1,s,t);     else     {         node res,s1,s2;         s1=query(l,mid,p<<1,s,mid);   s2=query(mid+1,r,(p<<1)+1,mid+1,t);         res.lc=s1.lc; res.rc=s2.rc;         res.v=s1.v+s2.v-(s1.rc==s2.lc);         return res;     } } void cover(int x,int y,int c) {     while (top[x]!=top[y])     {         if (dep[top[x]]<dep[top[y]]) swap(x,y);         update(1,n,1,id[top[x]],id[x],c);         x=fa[top[x]];     }     if (dep[x]>dep[y]) swap(x,y);     update(1,n,1,id[x],id[y],c); } int seg(int x,int y) {     int xc=-1,yc=-1,ans=0;     node now;     while (top[x]!=top[y])     {                   if (dep[top[x]]<dep[top[y]]) swap(x,y),swap(xc,yc);         now=query(1,n,1,id[top[x]],id[x]);         ans+=now.v-(now.rc==xc);         xc=now.lc; x=fa[top[x]];     }     if (dep[x]>dep[y]) swap(x,y),swap(xc,yc);     now=query(1,n,1,id[x],id[y]);     ans+=now.v-(now.lc==xc)-(now.rc==yc);     return ans;  } int main() {     scanf("%d%d",&n,&m);     for (int i=1; i<=n; i++)         scanf("%d",&fc[i]);     for (int i=1; i<n; i++)     {         scanf("%d%d",&u,&v);         add(u,v); add(v,u);     }     dfs1(1,0);     dfs2(1,1);     build(1,n,1);     while (m--)     {         scanf("%s",pd);         if (pd[0]=='C')          {             scanf("%d%d%d",&x,&y,&c);             c++;             cover(x,y,c);         }         if (pd[0]=='Q')         {             scanf("%d%d",&x,&y);             printf("%d\n",seg(x,y));         }     } } ?

原文:https://www.cnblogs.com/AGFghy/p/9362865.html

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!