题目:

BZOJ1483

分析:

(这题码了一下午,码了近250行,但是意外跑的比本校各位神仙稍快,特写博客纪念)

首先能看出一个显然的结论:颜色段数只会变少不会变多。

我们考虑用并查集维护区间,对于每个区间维护它的起点和终点。建\(n\)棵平衡树,第\(i\)棵存颜色为\(i\)的区间。把\(x\)变成\(y\)时进行启发式合并,同时对于\(x\)上的每个结点\([a,b]\),在\(y\)中找\(a-1\)和\(b+1\)所在区间。如果存在则合并,并答案减\(1\);若不存在则向\(y\)中插入新结点。时间复杂度\(O(m\log ^2n)\)

代码:

代码不难写,就是长……

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std; namespace zyt
{
template<typename T>
inline void read(T &x)
{
char c;
bool f = false;
x = 0;
do
c = getchar();
while (c != '-' && !isdigit(c));
if (c == '-')
f = true, c = getchar();
do
x = x * 10 + c - '0', c = getchar();
while (isdigit(c));
if (f)
x = -x;
}
template<typename T>
inline void write(T x)
{
static char buf[20];
char *pos = buf;
if (x < 0)
putchar('-'), x = -x;
do
*pos++ = x % 10 + '0';
while (x /= 10);
while (pos > buf)
putchar(*--pos);
}
const int N = 1e6 + 10;
int n, m, p[N], st[N], ed[N];
int f(const int x)
{
return x == p[x] ? x : p[x] = f(p[x]);
}
int ans = 0;
class Splay
{
private:
struct node
{
int val, size;
node *fa, *s[2];
node(const int _val, node *_fa)
: val(_val), fa(_fa)
{
size = 1;
s[0] = s[1] = NULL;
}
}*head;
bool dir(const node *rot)
{
return rot == rot->fa->s[1];
}
void update(node *rot)
{
rot->size = 1;
if (rot->s[0])
rot->size += rot->s[0]->size;
if (rot->s[1])
rot->size += rot->s[1]->size;
}
void rotate(node *rot)
{
node *f = rot->fa, *ff = f->fa;
bool d = dir(rot);
rot->fa = ff;
if (ff)
ff->s[dir(f)] = rot;
else
head = rot;
f->s[d] = rot->s[!d];
if (rot->s[!d])
rot->s[!d]->fa = f;
rot->s[!d] = f;
f->fa = rot;
update(f);
}
void splay(node *rot, const node *goal = NULL)
{
while (rot && rot->fa && rot->fa != goal)
{
node *f = rot->fa, *ff = f->fa;
if (ff == goal)
rotate(rot);
else if (dir(rot) ^ dir(f))
rotate(rot), rotate(rot);
else
rotate(f), rotate(rot);
}
update(rot);
}
void del(node *rot, Splay &s)
{
if (!rot)
return;
int x = f(rot->val);
bool flag = false;
if (st[x] > 1 && s.find(f(st[x] - 1)))
{
p[x] = f(st[x] - 1);
ed[f(st[x] - 1)] = ed[x];
--ans, flag = true;
}
x = f(x);
if (ed[x] < n && s.find(f(ed[x] + 1)))
{
p[x] = f(ed[x] + 1);
st[f(ed[x] + 1)] = st[x];
--ans, flag = true;
}
if (!flag)
s.insert(rot->val);
if (rot->s[0])
del(rot->s[0], s);
if (rot->s[1])
del(rot->s[1], s);
delete rot;
}
node *find(const int val)
{
node *rot = head;
while (1)
{
if (!rot || rot->val == val)
return rot;
if (val < rot->val)
rot = rot->s[0];
else
rot = rot->s[1];
}
}
public:
void insert(const int val)
{
if (!head)
{
head = new node(val, NULL);
return;
}
node *rot = head;
while (1)
{
if (val < rot->val)
{
if (rot->s[0])
rot = rot->s[0];
else
{
rot->s[0] = new node(val, rot);
splay(rot->s[0]);
break;
}
}
else
{
if (rot->s[1])
rot = rot->s[1];
else
{
rot->s[1] = new node(val, rot);
splay(rot->s[1]);
break;
}
}
}
}
size_t size()
{
if (head)
return head->size;
else
return 0;
}
friend void merge(Splay &a, Splay &b);
}tree[N];
inline void merge(Splay &a, Splay &b)
{
if (a.size() < b.size())
swap(a, b);
b.del(b.head, a);
b.head = NULL;
}
int arr[N], tmp[N];
int work()
{
read(n), read(m);
int last = 1;
for (int i = 1; i <= n; i++)
read(arr[i]);
p[1] = st[1] = ed[1] = 1;
for (int i = 2; i <= n; i++)
{
if (arr[i] != arr[i - 1])
{
tree[arr[i - 1]].insert(last);
st[i] = last = i, ++ans;
}
p[i] = last;
ed[last] = i;
}
tree[arr[n]].insert(last), ++ans;
while (m--)
{
int opt;
read(opt);
if (opt == 1)
{
int x, y;
read(x), read(y);
if (x != y)
merge(tree[y], tree[x]);
}
else
write(ans), putchar('\n');
}
return 0;
}
}
int main()
{
return zyt::work();
}

【BZOJ1483】[HNOI2009]梦幻布丁(平衡树启发式合并+并查集)的更多相关文章

  1. bzoj1483: [HNOI2009]梦幻布丁(vector+启发式合并)

    1483: [HNOI2009]梦幻布丁 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 4022  Solved: 1640[Submit][Statu ...

  2. bzoj1483: [HNOI2009]梦幻布丁(链表+启发式合并)

    题目大意:一个序列,两种操作. ①把其中的一种数修改成另一种数 ②询问有多少段不同的数如1 2 2 1为3段(1 / 2 2 / 1). 昨晚的BC的C题和这题很类似,于是现学现写居然过了十分开心. ...

  3. 【BZOJ1483】[HNOI2009]梦幻布丁 链表+启发式合并

    [BZOJ1483][HNOI2009]梦幻布丁 Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2 ...

  4. BZOJ 1483: [HNOI2009]梦幻布丁( 链表 + 启发式合并 )

    把相同颜色的串成一个链表, 然后每次A操作就启发式合并, 然后计算对答案的影响. ----------------------------------------------------------- ...

  5. BZOJ 1483: [HNOI2009]梦幻布丁 [链表启发式合并]

    1483: [HNOI2009]梦幻布丁 题意:一个带颜色序列,一种颜色合并到另一种,询问有多少颜色段 一种颜色开一个链表,每次遍历小的合并到大的里,顺带维护答案 等等,合并方向有规定? 令col[x ...

  6. bzoj 1483: [HNOI2009]梦幻布丁 (链表启发式合并)

    Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色. 例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. Input ...

  7. 洛谷P3201 [HNOI2009]梦幻布丁(链表 + 启发式合并)

    题目链接 给出 \(n\) 个布丁,每个补丁都有其颜色.现在有 \(m\) 次操作,每次操作将第 \(x_i\) 种颜色全部变为第 \(y_i\) 种颜色. 操作中可能会插入询问,回答目前总共有多少段 ...

  8. [BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并)

    [BZOJ 1483] [HNOI2009] 梦幻布丁 (线段树合并) 题面 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1 ...

  9. BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)

    不难...treap + 启发式合并 + 并查集 搞搞就行了 --------------------------------------------------------------------- ...

随机推荐

  1. Tornado进阶

    三.Tornado进阶 3.1 Application settings debug,设置tornado是否工作在调试模式,默认为False即工作在生产模式.当设置debug=True 后,torna ...

  2. JMeter测试websocket

    今天公司要测websocket,搞了一天踩了不少坑,关键是还没爬出来,BOSS让回家再理理思路,没办法到家就开干. 一.家里玩的还是2.1的,为了少踩坑,先下个JMeter5.1.1(他们说4版本也行 ...

  3. BZOJ 3747 洛谷 3582 [POI2015]Kinoman

    [题解] 扫描线+线段树. 我们记第i部电影上次出现的位置是$pre[i]$,我们从$1$到$n$扫描,每次区间$(pre[i],i]$加上第i部电影的贡献$w[f[i]]$,区间$[pre[pre[ ...

  4. dp专题备忘录

    hdu 1024:基础dp题 hdu 1029:主元素问题,很快的解法,计数器 hdu 1069:LIS hdu 1074:数位dp,数位dp基础 hdu 1257:简单LIS,要仔细分析为什么是求最 ...

  5. c# 缓存!

    做项目的时候获取所有城市的时候,发现每次去获取都花费了很多时间,所以用缓存方法让效率更高! 这是我做的例子,如下: public class CacheGetCity { /// <summar ...

  6. JQuery中如何重置(reset)表单(且清空隐藏域)

    由于JQuery中,提交表单是像下面这样的: 所以,想当然的认为,重置表单,当然就是像下面这样子喽: 但是,不幸的是,这样写的话,会有一个让你很郁闷的结果,那就是,表单无法重置! 后来,上网查了一下, ...

  7. Maven使用GitHub项目目录搭建远程仓库

    使用GtiHub的项目目录搭建第三方远程仓库,能免除使用服务器搭建Nexus私服,而且空间也是免费的.但是这种方式只适合小规模发布,毕竟搜索和版本控制是一个问题,如果需要更复杂的功能就只能转向Nexu ...

  8. ArcGIS 10 Engine DevelopKit 之安装与帮助;VBA,跨平台CPP,JAVA,ArcGIS Engine DevelopKit 10 的帮助如何打开

    你看到的这个文章来自于http://www.cnblogs.com/ayanmw ArcGIS Engine Developer Kit10 可以从VeryCD上下载到.其不需要破解,只需要你有一个已 ...

  9. 【转】gcov lcov 覆盖c/c++项目入门

    原文: http://www.cnblogs.com/turtle-fly/archive/2013/01/09/2851474.html ------------------------------ ...

  10. 第8章 处理ISDN故障

    第8章 处理ISDN故障 一.ISDN基本原理 二.常见ISDN故障 ISDN问题分成3类:配置不当的路由器.物理线缆和ISDN协议.配置不当的交换机. 1.配置不当的路由器 配置不当由于不同原因:t ...