刷题总结——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;
}
时间: 2024-10-01 06:31:19

刷题总结——bzoj2243染色的相关文章

7、8月刷题总结

准备开学了囧,7.8月刷题记录,以后好来复习,并且还要好好总结! 数据结构: splay: [BZOJ]1503: [NOI2004]郁闷的出纳员(Splay) [BZOJ]1269: [AHOI2006]文本编辑器editor(Splay) [BZOJ]1507: [NOI2003]Editor(Splay) treap: [BZOJ]1862: [Zjoi2006]GameZ游戏排名系统 & 1056: [HAOI2008]排名系统(treap+非常小心) [BZOJ]3224: Tyvj

BZOJ 刷题记录 PART 2

[前言]最近感觉状态不错.做题几乎不看题解了.(一群大牛(FZ&WCY)在旁边喷:你刷水题有意思!)但是至少这也是一种进步吧.特别是权限题中有很多思维题. [BZOJ1055]就是一个简单的区间DP.重要代码: for (l=2;l<=L;l++) for (i=1;i<=L-l+1;i++) { j=i+l-1; for (k=0;k<4;k++) for (cut=i;cut<j;cut++) for (p=0;p<4;p++) if (f[i][cut][p])

用js刷题的一些坑

leecode可以用js刷题了,我大js越来越被认可了是吧.但是刷题中会因为忽略js的一些特性掉入坑里.我这里总结一下我掉过的坑. 坑1:js中数组对象是引用对象 js中除了object还有数组对象也是引用对象,这点常常被忽视,所以在递归的时候传递数组要用arr.slice(0)这样复制一个一样的新数组,不然会出现你传入的数组会被同级的递归改变,结果就不对了. 所以只要数组复制的地方最好都要这么写,除非你真的想引用.而且注意是slice不是splice这两个方法差别很大,你如果用splice(0

LeetCode刷题之一:寻找只出现一次的数字

投简历的时候看到了个刷题网站,http://www.nowcoder.com/527604,就做了一套题,现记录下来. 题目为: Given an array of integers, every element appears twice except for one. Find that single one. Note: Your algorithm should have a linear runtime complexity. Could you implement it withou

【leetcode刷题笔记】Sum Root to Leaf Numbers

Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number. An example is the root-to-leaf path 1->2->3 which represents the number 123. Find the total sum of all root-to-leaf numbers. For example, 1 / 2 3 T

BZOJ第一页刷题计划

BZOJ第一页刷题计划 已完成:1 / 100 BZOJ1000:A+B

刷题记录

刷题啦,刷题啦,咱也刷算法题. 先从牛客网的JS方面刷起,接着刷数据结构和算法,然后去刷leetcode,这儿记载自己从出错的地方. 1.题目描述 移除数组 arr 中的所有值与 item 相等的元素,直接在给定的 arr 数组上进行操作,并将结果返回 . 没有认真思考,写下了如下的答案 function removeWithoutCopy(arr, item) { for(i = 0; i < arr.length; i++) { if( arr[i] === item) { arr.spli

停课刷题总结-给自己一点鼓励吧

嗯,我已经停了四五天课在家刷BZOJ准备复赛了,感觉压力好大.但是,实际上感觉效率并不高,每天就是7-8题的样子,而且并不是每题都有质量.而且这几天刷下来,我貌似因为刷了太多水题的关系,打字写题的速度变慢了,有一点悠闲没有紧迫感了,要赶快把这个习惯给改掉!今天去学校做题被虐了,竟然一个简单的Hash没有调对[虽然我现在还是不知道为什么会死循环QAQ.]感觉吧,可能因为刷题有点不在状态了.[其实也因为刷题的间隙玩了几盘LOL,游戏这东西QAQ]被虐了,感觉很不爽,有点难受,毕竟我付出了那么多努力,

leetcode 刷题之路 63 Binary Tree Zigzag Level Order Traversal

Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between). For example: Given binary tree {3,9,20,#,#,15,7}, 3 / 9 20 / 15 7 return its zig