P1903 [国家集训队]数颜色

题目描述

墨墨购买了一套\(N\)支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会向你发布如下指令:

1、Q L R代表询问你从第\(L\)支画笔到第\(R\)支画笔中共有几种不同颜色的画笔。

2、 R P Col 把第\(P\)支画笔替换为颜色\(Col\)。

为了满足墨墨的要求,你知道你需要干什么了吗?

输入输出格式

输入格式:

第1行两个整数\(N\),\(M\),分别代表初始画笔的数量以及墨墨会做的事情的个数。

第2行\(N\)个整数,分别代表初始画笔排中第i支画笔的颜色。

第3行到第2+M行,每行分别代表墨墨会做的一件事情,格式见题干部分。

输出格式:

对于每一个Query的询问,你需要在对应的行中给出一个数字,代表第L支画笔到第R支画笔中共有几种不同颜色的画笔。

说明

对于100%的数据,N≤50000,M≤50000,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。


正解是待修莫队,不过树套树复杂度更优秀(常数就不一定了),就拿树套树过了这个题

把一个颜色的笔放到一个set里,以位置为关键字,同时更新\(pre\)数组,代表前一个相同颜色的位置(特别的,如果没有,为0)

先不考虑修改,我们发现询问\([l,r]\)有多少不同颜色等价于询问有多少个\(pre\)数组小于\(l\),我们可以拿权值线段树解决这个问题

然后对于修改,我们只需要在外面套上树状数组就可以啦


Code:

#include <cstdio>
#include <algorithm>
#include <set>
#define ls ch[now][0]
#define rs ch[now][1]
using namespace std;
const int N=2e5+10;
int ch[N*18][2],sum[N*18],root[N],tot;
int a[N],b[N],pre[N],n,m,k;
void updata(int now){sum[now]=sum[ls]+sum[rs];}
void change(int &now,int l,int r,int pos,int delta)
{
if(!now) now=++tot;
if(l==r) {sum[now]+=delta;return;}
int mid=l+r>>1;
if(pos<=mid) change(ls,l,mid,pos,delta);
else change(rs,mid+1,r,pos,delta);
updata(now);
}
int query(int now,int l,int r,int pos)
{
if(!now||l==r) return 0;
int mid=l+r>>1;
if(pos<=mid) return query(ls,l,mid,pos);
else return sum[ls]+query(rs,mid+1,r,pos);
}
void modify(int x,int pos,int delta)
{
while(x<=n) change(root[x],0,n-1,pos,delta),x+=x&-x;
}
int ask(int x,int rk)
{
int ans=0;
while(x)
ans+=query(root[x],0,n-1,rk),x-=x&-x;
return ans;
}
struct node{int op,x,y;}opt[N];
set <int > rb[N];
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
m=n;char c[3];
for(int i=1;i<=k;i++)
{
scanf("%s%d%d",c,&opt[i].x,&opt[i].y);
opt[i].op=(c[0]=='R');
if(opt[i].op) a[++m]=opt[i].y;
}
sort(a+1,a+1+m);
m=unique(a+1,a+1+m)-a-1;
for(int i=1;i<=n;i++) b[i]=lower_bound(a+1,a+1+m,b[i])-a;
for(int i=1;i<=k;i++) if(opt[i].op) opt[i].y=lower_bound(a+1,a+1+m,opt[i].y)-a;
for(int i=1;i<=n;i++)
{
if(!rb[b[i]].empty())
{
set <int>::iterator it=rb[b[i]].end();
it--;
pre[i]=*it;
}
rb[b[i]].insert(i);
}
for(int i=1;i<=n;i++)
for(int j=i-(i&-i)+1;j<=i;j++)
change(root[i],0,n-1,pre[j],1);
for(int i=1;i<=k;i++)
{
if(opt[i].op)
{
int co=opt[i].y,pos=opt[i].x,pr;
set <int >::iterator it=rb[b[pos]].find(pos);//找到颜色位置
it++;
if(it!=rb[b[pos]].end())//改它的后继
{
modify(*it,pos,-1);
modify(*it,pre[*it]=pre[pos],1);
}
rb[b[pos]].erase(pos);//删掉
rb[b[pos]=co].insert(pos);//加入且改自己颜色
it=rb[co].find(pos);
if(it!=rb[co].begin()) it--,pr=*it,it++;
else pr=0;//找到pre
modify(pos,pre[pos],-1);//改自己pre
modify(pos,pre[pos]=pr,1);
it++;
if(it!=rb[b[pos]].end())//寻找后面
{
modify(*it,pre[*it],-1);
modify(*it,pre[*it]=pos,1);
}
}
else
printf("%d\n",ask(opt[i].y,opt[i].x)-opt[i].x+1);
}
return 0;
}

2018.9.4

洛谷 P1903 [国家集训队]数颜色 解题报告的更多相关文章

  1. BZOJ2120/洛谷P1903 [国家集训队] 数颜色 [带修改莫队]

    BZOJ传送门:洛谷传送门 数颜色 题目描述 墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. Q L R代表询问你从第L支画笔到第R ...

  2. ●洛谷P1903 [国家集训队]数颜色

    题链: https://www.luogu.org/problemnew/show/P1903题解: 序列带修莫队, 推荐博客https://www.cnblogs.com/Paul-Guderian ...

  3. 洛谷 P1903 [国家集训队]数颜色 / 维护队列

    墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: 1. \(Q\) \(L\) \(R\) 代表询问你从第L支画笔到第R支画笔中共有几种不同 ...

  4. [洛谷P1903][国家集训队]数颜色

    题目大意:有$n$支画笔,有两个操作 $Q\;l\;r:$询问$[l,r]$中有几种颜色 $R\;p\;Col:$把第$p$支画笔的颜色改成$Col$ 题解:带修莫队,分为$n^{\frac{1}{3 ...

  5. 洛谷P1903 [国家集训队]数颜色 / 维护队列 ( 带 修 )

    题意:有两种操作: 1. Q L R代表询问你从第L支画笔到第R支画笔中共有几种不同颜色的画笔. 2. R P Col 把第P支画笔替换为颜色Col. 对每个1操作 输出答案: 带修莫队 模板题 (加 ...

  6. 洛谷 P1903 [国家集训队]数颜色 / 维护队列 带修莫队

    题目描述 墨墨购买了一套\(N\)支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问.墨墨会向你发布如下指令: \(1\). \(Q\) \(L\) \(R\)代表询问你从第\(L\) ...

  7. 洛谷 P1903 [国家集训队]数颜色

    题意简述 给定一个数列,支持两个操作 1.询问l~r有多少不同数字 2.修改某个数字 题解思路 带修莫队 如果修改多了,撤销修改 如果修改少了,进行修改 代码 #include <cmath&g ...

  8. 洛谷 P1407 [国家集训队]稳定婚姻 解题报告

    P1407 [国家集训队]稳定婚姻 题目描述 我国的离婚率连续7年上升,今年的头两季,平均每天有近5000对夫妇离婚,大城市的离婚率上升最快,有研究婚姻问题的专家认为,是与简化离婚手续有关. 25岁的 ...

  9. 洛谷 P1852 [国家集训队]跳跳棋 解题报告

    P1852 [国家集训队]跳跳棋 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在\(a\),\(b\), ...

随机推荐

  1. Centos 7 下安装mysql

    // 卸载原有maridb-lib库 [root@localhost ~]# rpm -qa | grep mariadb mariadb-libs-5.5.41-2.el7_0.x86_64 [ro ...

  2. 《Linux就该这么学》,刘小伙实在人,给打个广告

    本书是由全国多名红帽架构师(RHCA)基于最新Linux系统共同编写的高质量Linux技术自学教程,极其适合用于Linux技术入门教程或讲课辅助教材,目前是国内最值得去读的Linux教材,也是最有价值 ...

  3. zip压缩工具,unzip解压缩工具

    zip压缩工具,unzip解压缩工具=================== [root@aminglinux tmp]# yum install -y zip[root@aminglinux tmp] ...

  4. C语言基础篇(三) 指针

    导航: 1.指针     2. 数组     3. 结构体,共用体     4. 内存分布图     5. 段错误分析 ----->x<------------->x<---- ...

  5. C——可变参数

    1.要学可变参数,需要先了解C编译器对栈的管理 做个实验可以得到 #include <stdio.h> void func(int a, char b, int c, int d) { i ...

  6. P1219 N皇后

    P1219 N皇后 题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序 ...

  7. 2018Ec-Final比赛总结

    一场匆忙的旅程. NCC_9754_ Victory的最后一场比赛终究没能victory. 去的时候晕车到吐了两次,到宾馆吃完饭直接睡了,但还是两天都昏昏沉沉的头疼的厉害,第二天直接步行去了西工大体育 ...

  8. json loads/dumps

    json.dumps : dict转成str json.loads:str转成dict dict_ = {1: 2, 3: 4, "} print(type(dict_), dict_) # ...

  9. Android getLocationInWindow

    参考博客: http://blog.sina.com.cn/s/blog_44d19b500102vpve.html 这篇博客,我看了三遍,终于看懂了.恩,我就喜欢这样不放弃的自己. 1.getLoc ...

  10. [转]Android进程间通信--消息机制及IPC机制实现

    Android为了屏蔽进程的概念,利用不同的组件[Activity.Service]来表示进程之间的通信! 组件间通信的核心机制是Intent,通过Intent可以开启一个Activity或Servi ...