「HNOI2009」 梦幻布丁 - 线段树合并

2024-01-02 07:48

本文主要是介绍「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 &lt; N , M &lt; 100001 0&lt;N,M&lt;100001 0<N,M<100001
0 &lt; A i , x , y &lt; 1000000 0&lt;A_i,x,y&lt;1000000 0<Ai,x,y<1000000

分析

可以对种颜色开一棵线段树,范围为1~n,表示在区间中为改颜色的位置,同时线段树中记录区间内的段数,为左+右,若中间都有,则减1。对于颜色变换,直接线段树合并即可,注意同时维护答案。

注意,对于根节点不能开1000000的数组存,只能用STL map,数组空间开不下,会爆系统栈,然后发生越界现象,然后就有许多莫名奇妙的错误,比如WaTLE等。

代码

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <map>
using namespace std;
const int N=100010,M=1000005;
const int LogN=20;
typedef struct SegmentTree {int l,r,ls,rs,len;
}Segment,SegT;
SegT nd[N*LogN];
int tot;
int st[N*LogN],top;
int n,m,ans,app[N];
map<int,int> rt;
void Clear(int x) {nd[x].l=nd[x].r=0;nd[x].len=nd[x].ls=nd[x].rs=0;
}
int New() {if (top) return Clear(st[top]),st[top--];else return ++tot;
}
void Pushup(int x) {int lc=nd[x].l,rc=nd[x].r;nd[x].len=nd[lc].len+nd[rc].len;if (nd[lc].rs&&nd[rc].ls) nd[x].len--;nd[x].ls=nd[lc].ls;nd[x].rs=nd[rc].rs;
}
void Add(int &rt,int l,int r,int x,int v) {if (!rt) {rt=New();nd[rt].l=nd[rt].r=0;}if (l==r) {nd[rt].len+=v;nd[rt].ls+=v;nd[rt].rs+=v;return;}int mid=(l+r)>>1;if (x<=mid) Add(nd[rt].l,l,mid,x,v);else Add(nd[rt].r,mid+1,r,x,v);Pushup(rt);
}
void Recycle(int &y) {st[++top]=y;Clear(y);y=0;
}
void Merge(int l,int r,int&x,int &y) {//x<-y;if (!y) return;if (!x) {x=New();nd[x]=nd[y];Recycle(y);return;}if (l==r) {nd[x].len=nd[y].len;nd[x].ls=nd[y].ls;nd[x].rs=nd[y].rs;Recycle(y);return;}int mid=(l+r)>>1;Merge(l,mid,nd[x].l,nd[y].l);Merge(mid+1,r,nd[x].r,nd[y].r);Recycle(y);Pushup(x);
}
int main() {scanf("%d%d",&n,&m);for (int i=1;i<=n;i++) {int cl;scanf("%d",&cl);app[i]=cl;Add(rt[cl],1,n,i,1);}sort(app+1,app+n+1);int n_=unique(app+1,app+n+1)-app-1;for (int i=1;i<=n_;i++)ans+=nd[rt[app[i]]].len;for (int i=1;i<=m;i++) {int op,x,y;scanf("%d",&op);if (op==2) printf("%d\n",ans);else {scanf("%d%d",&x,&y);//x->y;if (x==y) continue;ans-=nd[rt[x]].len;ans-=nd[rt[y]].len;Merge(1,n,rt[y],rt[x]);ans+=nd[rt[y]].len;}}return 0;
}

这篇关于「HNOI2009」 梦幻布丁 - 线段树合并的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/561781

相关文章

JeecgBoot v3.7.0 all 版本发布,前后端合并一个仓库

项目介绍 JeecgBoot是一款企业级的低代码平台!前后端分离架构 SpringBoot2.x,SpringCloud,Ant Design&Vue3,Mybatis-plus,Shiro,JWT 支持微服务。强大的代码生成器让前后端代码一键生成! JeecgBoot引领低代码开发模式(OnlineCoding-> 代码生成-> 手工MERGE), 帮助解决Java项目70%的重复工作,让开

Python批量读取csv文件并合并文件

import pandas as pdimport os # 获取当前路径cwd = os.getcwd()# 要拼接的文件夹及其完整路径,注不要包含中文## 待读取批量csv的文件夹 read_path = 'data_Q1_2018' ## 待保存的合并后的csv的文件夹 save_path = 'data_Q1_2018_merge' ## 待保存

线段树单点修改的应用

思路:对初始状态进行建树,然后这题就相当于查询第一个合法的位置,并且对其值进行修改,整个题目要求维护的是区间最大值,很显然可以使用线段树。 #include <bits/stdc++.h>using namespace std;const int N = 2e6 + 5;typedef long long ll;typedef pair<ll, ll> pll;typedef arra

合并有序链表

合并有序链表 图解代码如下 图解 虽然很复杂,但能够很好的理解怎么使用链表,以及对链表的指针类理解 代码如下 Node* merge_list_two_pointer(List& list1, List& list2){Node* new_head1 = list1.head;Node* new_head2 = list2.head;Node* sentinel1 =

技巧:合并多个RAR分卷压缩

因为文件压缩之后体积仍然过大,大家可能会选择进行分卷压缩,那么rar分卷压缩包之后如何合并成一个压缩包文件呢?今天我们来学习rar分卷压缩包,合并成一个的方法。 最基础的方法就是将分卷压缩包解压出来之后,再将文件进行合并,这个方法就不再赘述,下面是更方便的操作方法。 这个方法利用我之前分享过的压缩包格式转换功能,我们打开WinRAR,找到功能栏中【工具】-【转换压缩文件格式】 在转换压缩

Studying-代码随想录训练营day17| 654.最大二叉树、617合并二叉树、700.二叉搜索树中的搜索、98.验证二叉树搜索树

第十七天,二叉树part05,进一步学习二叉树💪 654.最大二叉树 文档讲解:代码随想录最大二叉树 视频讲解:手撕最大二叉树 题目: 学习:本题与利用中序和后序序列构造二叉树有相同之处。依据题目要求,首先在数组里面找到最大值,作为根节点,然后划分左右区间对应根节点的左右子树。再分别在左右区间中找到最大值,作为根节点(中间节点),之后再次划分区间,进行下一轮循环。 代码:

【位操作笔记】位合并 通过掩码

位合并(Merge bits) 通过掩码 通过掩码把两个数进行位合并。例如一个数为0x23,另一个数为0x65,假设合并的数要取第一个数的高4位,第二个数的低4位,那么合并后的数就是0x25。 算法说明 该算法使用了异或来实现,比普通的实现方式节省一次操作。 实现代码 non_masked_val和masked_val是两个要进行合并的数,mask是掩码。 non_masked_val

【位操作笔记】位合并 普通方式

位合并(Merge bits) 普通方式 通过掩码把两个数进行位合并。例如一个数为0x23,另一个数为0x65,假设合并的数要取第一个数的高4位,第二个数的低4位,那么合并后的数就是0x25。 算法说明 该算法通过先与掩码,再进行或操作完成。 实现代码 non_masked_val和masked_val是两个要进行合并的数,mask是掩码。 non_masked_val是合并非掩码位,

视频剪辑技巧大揭秘:轻松掌握为视频添加梦幻光晕效果的绝妙方法!

在这个视觉盛宴的时代,每一个画面都渴望被赋予独特的魅力与魔法。今天,我要为你揭秘一个神秘的视频剪辑技巧——给视频添加光晕效果,让你的作品瞬间脱颖而出,成为朋友圈的焦点 首先,你可以打开原视频进行查看。此时,你会发现视频中的画面虽然真实,但却缺乏那种令人心动的梦幻感。不要担心,这正是我们接下来要为你解决的难题! 当你打开视频剪辑高手的主页面,首先映入眼帘的便是简洁明了的操作界面和高效实用

[HDU 5029] Relief grain (树链剖分+线段树)

HDU - 5029 其实这道题最大的难点不是树链剖分,而是怎么维护某个点被那些颜色染过,染过多少次 如果在线段树维护的话,很难做到,估计得树套树,而且空间会炸 好在这题是离线的,可以使用差分的思想来维护 对一段区间[l,r]染色 c,相当于在这段区间左端点 l打上 c标志,右端点 r+1打上 -c标志 然后扫一遍整个区间 (依照 dfs序扫一遍整棵树),期间不断维护一颗线段树 线段树