P3201 [HNOI2009]梦幻布丁
题目描述
N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色.
输入输出格式
输入格式:
第一行给出N,M表示布丁的个数和好友的操作次数.
第二行N个数A1,A2...An表示第i个布丁的颜色从第三行起有M行,对于每个操作,若第一个数字是1表示要对颜色进行改变,其后的两个整数X,Y表示将所有颜色为X的变为Y,X可能等于Y.
若第一个数字为2表示要进行询问当前有多少段颜色,这时你应该输出一个整数. 0
输出格式:
针对第二类操作即询问,依次输出当前有多少段颜色.
输入输出样例
4 3
1 2 2 1
2
1 2 1
2
3
1
说明
1<=n,m<=100,000; 0<Ai,x,y<1,000,000
Solution:
本题平衡树+启发式合并。
考试的时候没有注意$x==y$的情况,结果只对了8个点,GG。
思路比较简单,我们用多棵平衡树维护每种颜色的下标,在对一种颜色的平衡树进行操作的同时可以处理出这个颜色的连续段数,具体来说,对于一种颜色,若新加入一个节点,就判断该节点能否与其前趋或者后继相接,讨论一下各种情况就好了。
在合并的时候用启发式的思想把节点少的树的每个节点暴力加入节点多的树中,若$size$少的树是变换后的颜色所在树,直接交换两种颜色的树根就可以了。
查询就直接输出全局的答案。
时间复杂度:$O(n\log ^2 n)$
(坑点:$x==y$时不需要操作)
代码:
/*Code by 520 -- 10.25*/
#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
#define debug printf("%s %d\n",__FUNCTION__,__LINE__)
using namespace std;
const int N=1e6+;
int n,m,root[N],ans,sum[N];
int col[N],ch[N][],cnt,fa[N],rnd[N],siz[N],date[N]; int gi(){
int a=;char x=getchar();
while(x<''||x>'') x=getchar();
while(x>=''&&x<='') a=(a<<)+(a<<)+(x^),x=getchar();
return a;
} il int newnode(int v){
++cnt;
date[cnt]=v,rnd[cnt]=rand(),siz[cnt]=,fa[cnt]=;
return cnt;
} il void up(int rt){
if(ch[rt][]) fa[ch[rt][]]=rt;
if(ch[rt][]) fa[ch[rt][]]=rt;
siz[rt]=siz[ch[rt][]]+siz[ch[rt][]]+;
} int merge(int x,int y){
if(!x||!y) return x+y;
if(rnd[x]<rnd[y]) {ch[x][]=merge(ch[x][],y),up(x);return x;}
else {ch[y][]=merge(x,ch[y][]),up(y);return y;}
} void split(int rt,int v,int &x,int &y){
if(!rt) {x=y=;return ;}
if(date[rt]>v) y=rt,split(ch[rt][],v,x,ch[y][]),up(y);
else x=rt,split(ch[rt][],v,ch[x][],y),up(x);
} il int kth(int rt,int v){
while(){
if(siz[ch[rt][]]>=v) rt=ch[rt][];
else if(siz[ch[rt][]]+<v) v-=siz[ch[rt][]]+,rt=ch[rt][];
else return rt;
}
} il int pre(int id,int v){
int x,y,ans; split(root[id],date[v]-,x,y);
ans=(!siz[x])?-:(kth(x,siz[x]));
root[id]=merge(x,y),fa[root[id]]=;
return ans;
} il int suc(int id,int v){
int x,y,ans; split(root[id],date[v],x,y);
ans=(!siz[y])?-:(kth(y,));
root[id]=merge(x,y),fa[root[id]]=;
return ans;
} il void ins(int id,int v){
int x=pre(id,v),y=suc(id,v);
if(x>&&y>&&date[x]==date[v]-&&date[y]==date[v]+) ans--,sum[id]--;
else if(x<&&y<||x>&&date[x]!=date[v]-&&(y<||date[y]!=date[v]+)||y>&&date[y]!=date[v]+&&(x<||date[x]!=date[v]-)) ans++,sum[id]++;
x=y=;
split(root[id],date[v]-,x,y),root[id]=merge(merge(x,v),y),fa[root[id]]=;
} void dfs(int id,int rt){
if(!rt) return;
dfs(id,ch[rt][]),dfs(id,ch[rt][]);
ch[rt][]=ch[rt][]=;
ins(id,rt);
} int main(){
n=gi(),m=gi(); int opt,x,y;
For(i,,n) {
col[i]=gi();
ins(col[i],newnode(i));
}
while(m--){
opt=gi();
if(opt==) {
x=gi(),y=gi();
if(x==y) continue;
else if(siz[root[x]]<=siz[root[y]]){
dfs(y,root[x]),root[x]=;ans-=sum[x],sum[x]=;
}
else {
swap(root[x],root[y]),swap(sum[x],sum[y]);
dfs(y,root[x]),root[x]=;ans-=sum[x],sum[x]=;
}
}
else printf("%d\n",ans);
}
return ;
}
P3201 [HNOI2009]梦幻布丁的更多相关文章
- 洛谷P3201 [HNOI2009]梦幻布丁 [链表,启发式合并]
题目传送门 梦幻布丁 题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. 输入输 ...
- 洛谷P3201 [HNOI2009]梦幻布丁(链表 + 启发式合并)
题目链接 给出 \(n\) 个布丁,每个补丁都有其颜色.现在有 \(m\) 次操作,每次操作将第 \(x_i\) 种颜色全部变为第 \(y_i\) 种颜色. 操作中可能会插入询问,回答目前总共有多少段 ...
- 洛谷P3201 [HNOI2009]梦幻布丁
题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. 输入输出格式 输入格式: 第 ...
- luogu P3201 [HNOI2009]梦幻布丁
传送门 先考虑暴力,显然每次是把一个位置集合和另一个集合合并,同时维护答案,合并的过程中如果两个集合每有一对元素相邻,答案就减1 优化暴力的话,说到合并,怎么能不想起启发式合并呢?每次把一个大小小的集 ...
- 洛谷 P3201 [HNOI2009]梦幻布丁(启发式合并)
题面 luogu 题解 什么是启发式合并? 小的合并到大的上面 复杂度\(O(nlogn)\) 这题颜色的修改,即是两个序列的合并 考虑记录每个序列的\(size\) 小的合并到大的 存序列用链表 但 ...
- bzoj 1483 [HNOI2009]梦幻布丁(链表+启发式合并)
1483: [HNOI2009]梦幻布丁 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1818 Solved: 761[Submit][Status ...
- BZOJ 1483: [HNOI2009]梦幻布丁( 链表 + 启发式合并 )
把相同颜色的串成一个链表, 然后每次A操作就启发式合并, 然后计算对答案的影响. ----------------------------------------------------------- ...
- BZOJ 1483: [HNOI2009]梦幻布丁 [链表启发式合并]
1483: [HNOI2009]梦幻布丁 题意:一个带颜色序列,一种颜色合并到另一种,询问有多少颜色段 一种颜色开一个链表,每次遍历小的合并到大的里,顺带维护答案 等等,合并方向有规定? 令col[x ...
- [HNOI2009] 梦幻布丁
[HNOI2009] 梦幻布丁 标签: 链表 题解 可以直接用链表启发式合并做. 合并的细节处理稍微有点麻烦. 假如需要变成另一种颜色的那个颜色的个数更多,那么就肯定不能直接合. 维护一个color数 ...
随机推荐
- [01] MyBatis概述
传统的JDBC来做DAO层,做了下面这几件事: 加载驱动 获取连接 执行SQL语句 获取操作结果封装信息 返回操作结果 而实际上DAO层最关心的是什么呢,就是后面三点就完事,JDBC显得太繁琐: 执行 ...
- python中的 sql语句用法
函数中应用sql语句def _get_cust_number(self,cr,uid,ids,field_name,args,context=None): res={} for order in se ...
- 算法相关——Java排序算法之快速排序(三)
0. 前言 本系列文章将介绍一些常用的排序算法.排序是一个非常常见的应用场景,也是开发岗位面试必问的一道面试题,有人说,如果一个企业招聘开发人员的题目中没有排序算法题,那说明这个企业不是一个" ...
- Luogu P4427 [BJOI2018]求和
这是一道巨狗题,我已无力吐槽为什么我怎么写都不过 我们对于这种无修改的边权题目有一个经典的树上差分套路: \(ans=sum_x+sum_y-2\cdot sum_{LCA(x,y)}\) 这里的\( ...
- 【react】使用 create-react-app 构建基于TypeScript的React前端架构----上
写在前面 一直在探寻,那优雅的美:一直在探寻,那精湛的技巧:一直在探寻,那简单又直白,优雅而美丽的代码. ------ 但是在JavaScript的动态类型.有时尴尬的自动类型转换,以及 “0 == ...
- Linux下环境变量配置方法梳理(.bash_profile和.bashrc的区别)
在linux系统下,如果下载并安装了应用程序,在启动时很有可能在键入它的名称时出现"command not found"的提示内容.如果每次都到安装目标文件夹内,找到可执行文件来进 ...
- Python运算符-4
#and or not #优先级,()> not > and > or print(2 > 1 and 1 < 4) print(2 > 1 and 1 < ...
- Code Review —— by12061154Joy
对结对队友刘丽萍的代码进行了复审: 优点: 1,代码逻辑正确,基本能够完全需求 2,用了不少C#自带的函数,第一次写C#,相信是查阅了不少资料,虽然还有很多地方值得优化,不过第一次能做到这样已经很不错 ...
- SCRUM 12.18
明天就是编译课设的第二次中期考核了,大家都感到有一些压力. 所以我们决定今天减少一些工作量. 工作任务分配依旧如往常 成员 任务 彭林江 落实API 郝倩 研究遍历美团数据方法 牛强 落实意见反馈功能 ...
- 【个人博客作业II】有关代码规范问题的讨论
参考课程辅导书<构建之法>可以知道,程序的代码规范常指代码风格规范和代码设计规范两个方面,其中:代码风格规范包括(缩进,行宽,括号,断行与空白行,分行,命名,下划线,大小写,注释这几个部分 ...