刷题总结——bzoj2243染色

题目:

题目背景

SDOI2011 DAY1 T3 

题目描述

给定一棵有 n 个节点的无根树和 m 个操作,操作有 2 类:
1、将节点 a 到节点 b 路径上所有点都染成颜色 c ;
2、询问节点 a 到节点 b 路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由 3 段组:“11”、“222”和“1”。
请你写一个程序依次完成这 m 个操作。

输入格式

第一行包含 2 个整数 n 和 m ,分别表示节点数和操作数;
第二行包含 n 个正整数表示 n 个节点的初始颜色;
下面 n-1 行每行包含两个整数 x 和 y ,表示 x 和 y 之间有一条无向边。
下面 m 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点 a 到节点 b 路径上所有点(包括a和b)都染成颜色;
“Q  a  b”表示这是一个询问操作,询问节点 a 到节点 b(包括a和b)路径上的颜色段数量。

输出格式

对于每个询问操作,输出一行答案。

样例数据 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

输出



2

备注

【数据范围】

对于测试点 7、8、9、10,树是这样生成的:
随机生成一个 1~n 的排列 p ,设 p1为根。对于2≤i≤n,pi 的父亲为 Prandom(1,i-1),其中 Prandom(a,b)以相等的概率返回 {x∈Z|a≤x≤b}中的一个元素,然后将所有边打乱顺序后作为输入提供给你的程序。

【友情提示】 
不允许使用编译开关改变栈空间大小,请选手尽量不要使用递归,以避免堆栈溢出。

题解:

树链剖分题···注意维护线段树时的一些小细节即可

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
using namespace std;
const int N=1e5+5;
int first[N],go[N*2],next[N*2],son[N],size[N],idx[N],pos[N],father[N],deep[N],top[N],tot;
int color[N],Left[N*4],Right[N*4],num[N*4],cnt,n,m,lazy[N*4];
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<'0'||c>'9';c=getchar());
  for(;c<='9'&&c>='0';c=getchar())
    f=(f<<3)+(f<<1)+c-'0';
  return f;
}
inline void comb(int a,int b)
{
  next[++tot]=first[a],first[a]=tot,go[tot]=b;
  next[++tot]=first[b],first[b]=tot,go[tot]=a;
}
inline void dfs1(int u,int fa)
{
  size[u]=1;
  for(int e=first[u];e;e=next[e])
  {
    int v=go[e];
    if(v==fa)  continue;
    father[v]=u;deep[v]=deep[u]+1;
    dfs1(v,u);
    size[u]+=size[v];
    if(size[v]>size[son[u]])  son[u]=v;
  }
}
inline void dfs2(int u)
{
  if(son[u])
  {
    idx[pos[son[u]]=++cnt]=son[u];
    top[son[u]]=top[u];
    dfs2(son[u]);
  }
  for(int e=first[u];e;e=next[e])
  {
    int v=go[e];
    if(v==father[u]||v==son[u])  continue;
    idx[pos[v]=++cnt]=v;top[v]=v;
    dfs2(v);
  }
}
inline void build(int k,int l,int r)
{
  if(l==r)
  {
    num[k]=1;
    Right[k]=Left[k]=color[idx[l]];
    return;
  }
  int mid=(l+r)/2;
  build(k*2,l,mid);build(k*2+1,mid+1,r);
  Right[k]=Right[k*2+1];Left[k]=Left[k*2];
  if(Right[k*2]==Left[k*2+1])  num[k]=num[k*2]+num[k*2+1]-1;
  else num[k]=num[k*2]+num[k*2+1];
} 
inline void tag(int k,int c)
{
  Left[k]=Right[k]=c;
  num[k]=1;
  lazy[k]=c;
}
inline void pushdown(int k)
{
  if(lazy[k]!=-1)
  {
    tag(k*2,lazy[k]);
    tag(k*2+1,lazy[k]);
    lazy[k]=-1;
  }
}
inline void modify(int k,int l,int r,int x,int y,int c)
{
  if(l>=x&&y>=r)
  {
    tag(k,c);
    return;
  }
  int mid=(l+r)/2;
  pushdown(k);
  if(x<=mid)  modify(k*2,l,mid,x,y,c);
  if(y>mid)  modify(k*2+1,mid+1,r,x,y,c);
  Right[k]=Right[k*2+1];Left[k]=Left[k*2];
  if(Right[k*2]==Left[k*2+1])  num[k]=num[k*2]+num[k*2+1]-1;
  else num[k]=num[k*2]+num[k*2+1];
}
inline int query(int k,int l,int r,int x,int y)
{
  if(l>=x&&y>=r)
    return num[k];
  int mid=(r+l)/2;
  pushdown(k);
  int ans=0;
  if(x<=mid)  ans+=query(k*2,l,mid,x,y);  
  if(y>mid)  ans+=query(k*2+1,mid+1,r,x,y);
  if(Right[k*2]==Left[k*2+1]&&x<=mid&&y>mid)  return ans-1;
  else return ans;
}
inline void modifypath(int a,int b,int c)
{
  if(top[a]!=top[b])
  {
    if(deep[top[a]]<deep[top[b]])  swap(a,b);
    modify(1,1,n,pos[top[a]],pos[a],c);
    modifypath(father[top[a]],b,c);
  }
  else
  {
    if(deep[a]<deep[b])  swap(a,b);
    modify(1,1,n,pos[b],pos[a],c);
  }
}
inline int queryc(int k,int l,int r,int x)
{
  if(l==r)
    return Left[k];
  int mid=(l+r)/2;
  pushdown(k);
  if(x<=mid)  return queryc(k*2,l,mid,x);
  else return queryc(k*2+1,mid+1,r,x);
}
inline int querypath(int a,int b)
{
  if(top[a]!=top[b])
  {  
    if(deep[top[a]]<deep[top[b]])  swap(a,b);
    if(queryc(1,1,n,pos[top[a]])==queryc(1,1,n,pos[father[top[a]]]))  
      return querypath(father[top[a]],b)+query(1,1,n,pos[top[a]],pos[a])-1;  
    else return querypath(father[top[a]],b)+query(1,1,n,pos[top[a]],pos[a]);
  }
  else
  {
    if(deep[a]<deep[b])  swap(a,b);
    return query(1,1,n,pos[b],pos[a]);
  }
}
int main()
{
  //freopen("a.in","r",stdin);
  n=R(),m=R();int a,b,c;char s[5];
  for(int i=1;i<=n*4;i++)
    lazy[i]=-1;
  for(int i=1;i<=n;i++)  color[i]=R();
  for(int i=1;i<n;i++)
  {
    a=R(),b=R();
    comb(a,b);
  }
  dfs1(1,0);
  pos[1]=top[1]=idx[1]=cnt=1;
  dfs2(1);
  build(1,1,n);
  while(m--)
  {
    scanf("%s",s);
    if(s[0]=='C')
    {
      a=R(),b=R(),c=R();
      modifypath(a,b,c);
    }
    else
    {
      a=R(),b=R();
      cout<<querypath(a,b)<<endl;
    }
  }
  return 0;
}

 

posted @ 2017-09-06 20:41  AseanA  阅读(166)  评论(0编辑  收藏  举报