【SDOI2011】染色

Ahead

10.5.2018

分析

树链剖分之后,用线段树维护区间,对于修改直接对线段树区间修改,如果左儿子的右端点颜色等于右儿子的左端点颜色则上传时父亲节点的sum要减1 因为两个子节点的中间区间合并了。 对于查询的话,每次跨链的查询要寻找链顶端的颜色和其父节点的颜色是否一样,如果一样就要减1 因为这里同样可以合并,统计就放到后面就可以了
200行代码祭+两个小时的调试青春

代码

#include <bits/stdc++.h>
using namespace std;

inline int read()
{
  int x=0;
  char c=getchar();
  while(c<'0' || c>'9') c=getchar();
  while(c<='9' && c>='0')
  {
    x=(x<<1)+(x<<3)+c-'0';
    c=getchar();
  }
  return x;
}

const int N = 1e5+100;
int n,m,col[N];
char ch[10];

int len,to[N<<1],nxt[N<<1],last[N];
inline void ins(int x,int y)
{
  to[++len]=y,nxt[len]=last[x],last[x]=len;
}

int dep[N],fa[N],son[N],tot[N];
void dfs1(int x)
{
  tot[x]=1;
  for(int k=last[x]; k; k=nxt[k])
  {
    int y=to[k];
    if(y!=fa[x])
    {
      fa[y]=x;
      dep[y]=dep[x]+1;
      dfs1(y);
      tot[x]+=tot[y];
      if(tot[y]>tot[son[x]]) son[x]=y;
    }
  }
}

int top[N],pos[N],rpos[N],tim;
void dfs2(int x,int tp)
{
  top[x]=tp,pos[x]=++tim,rpos[tim]=x;
  if(!son[x]) return ;
  dfs2(son[x],tp);
  for(int k=last[x]; k; k=nxt[k])
  {
    int y=to[k];
    if(y!=fa[x] && y!=son[x]) dfs2(y,y);
  }
}

struct node
{
  int l,r,lcol,rcol,sum,lazy;
} e[N<<2];

inline void push_up(int now)
{
  e[now].sum=e[now<<1].sum+e[now<<1|1].sum;
  if(e[now<<1].rcol==e[now<<1|1].lcol)
    e[now].sum--;
  e[now].lcol=e[now<<1].lcol;
  e[now].rcol=e[now<<1|1].rcol;
}

inline void push_down(int now)
{
  e[now<<1].lcol=e[now<<1].rcol=e[now].lcol;
  e[now<<1|1].lcol=e[now<<1|1].rcol=e[now].rcol;
  e[now<<1].lazy=e[now<<1|1].lazy=e[now].lazy;
  e[now<<1].sum=e[now<<1|1].sum=1;
  e[now].lazy=0;
}

void bt(int now ,int l,int r)
{
  e[now].l=l,e[now].r=r;
  if(l>=r)
  {
    e[now].lcol=e[now].rcol=col[rpos[l]];
    e[now].sum=1;
    return ;
  }
  int mid=(l+r)>>1;
  bt(now<<1,l,mid);
  bt(now<<1|1,mid+1,r);
  push_up(now);
}

int sum(int now,int l,int r)
{
  int ans=0;
  if(e[now].l==l&&e[now].r==r) return e[now].sum;
  if(e[now].lazy) push_down(now);
  int mid=(e[now].l+e[now].r)>>1;
  if(r<=mid) ans=sum(now<<1,l,r);
  else if(l>mid) ans=sum(now<<1|1,l,r);
  else
  {
    ans=sum(now<<1,l,mid)+sum(now<<1|1,mid+1,r);
    if(e[now<<1].rcol==e[now<<1|1].lcol) ans--;
  }
  push_up(now);
  return ans;
}

int record(int now ,int k)
{
  if(e[now].l==e[now].r) return e[now].lcol;
  if(e[now].lazy) push_down(now);
  int mid=(e[now].l+e[now].r)>>1;
  if(k<=mid) return record(now<<1,k);
  else return record(now<<1|1,k);
}

inline int query(int x,int y)
{
  int ans=0,tx=top[x],ty=top[y],tmp1,tmp2;
  while(tx!=ty)
  {
    if(dep[tx]>dep[ty]) swap(x,y),swap(tx,ty);
    ans+=sum(1,pos[ty],pos[y]);
    tmp1=record(1,pos[ty]);
    tmp2=record(1,pos[fa[ty]]);
    if(tmp1==tmp2) ans--;
    y=fa[ty];
    ty=top[y];
  }
  if(dep[x]>dep[y]) swap(x,y);
  ans+=sum(1,pos[x],pos[y]);
  return ans;
}

void up_data(int now ,int l,int r,int k)
{
  if(e[now].l==l && e[now].r==r)
  {
    e[now].lcol=e[now].rcol=k;
    e[now].lazy=k;
    e[now].sum=1;
    return ;
  }
  if(e[now].lazy) push_down(now);
  int mid=(e[now].l+e[now].r)>>1;
  if(r<=mid) up_data(now<<1,l,r,k);
  else if(l>mid) up_data(now<<1|1,l,r,k);
  else
  {
    up_data(now<<1,l,mid,k);
    up_data(now<<1|1,mid+1,r,k);
  }
  push_up(now);
}

inline void updata(int x,int y,int c)
{
  int tx=top[x],ty=top[y];
  while(tx!=ty)
  {
    if(dep[tx]>dep[ty]) swap(x,y),swap(tx,ty);
    up_data(1,pos[ty],pos[y],c);
    y=fa[ty];
    ty=top[y];
  }
  if(dep[x]>dep[y]) swap(x,y);
  up_data(1,pos[x],pos[y],c);
}

int main()
{
  int x,y,z;
  n=read(),m=read();
  for(int i=1; i<=n; ++i) col[i]=read();
  for(int i=1; i<n; ++i)
  {
    x=read(),y=read();
    ins(x,y);
    ins(y,x);
  }
  dep[1]=1;
  dfs1(1);
  dfs2(1,1);
  /*for(int i=1; i<=n; ++i)
    printf("ddd %d\n",pos[i]);*/
  bt(1,1,tim);
  while(m--)
  {
    scanf("%s",ch);
    if(ch[0]=='Q')
    {
      x=read(),y=read();
      printf("%d\n",query(x,y));
    }
    else if(ch[0]=='C')
    {
      x=read(),y=read(),z=read();
      updata(x,y,z);
    }
  }
  return 0;
}

posted @ 2018-10-05 21:06  PiCaHor  阅读(132)  评论(0编辑  收藏  举报