题目描述

墨墨购买了一套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支画笔中共有几种不同颜色的画笔。

样例输入

6 5
1 2 3 4 5 5
Q 1 4
Q 2 6
R 1 2
Q 1 4
Q 2 6

样例输出

4
4
3
4

提示

对于100%的数据,N≤10000,M≤10000,修改操作不多于1000次,所有的输入数据中出现的所有整数均大于等于1且不超过10^6。

 
带修改莫队模板题

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
struct lty
{
int l,r,num,tim;
}q[10010];
struct miku
{
int x,y;
}a[10010];
int res;
int v[1000010];
int s[100010];
int ans[100010];
int num,cnt;
int n,m;
int block;
char ch[20];
bool cmp(lty a,lty b)
{
return (a.l/block==b.l/block)?(a.r==b.r?a.tim<b.tim:a.r<b.r):a.l<b.l;
}
void del(int x)
{
if(v[x]==1)
{
res--;
}
v[x]--;
}
void ins(int x)
{
if(!v[x])
{
res++;
}
v[x]++;
}
void change(int l,int r,int id)
{
if(a[id].x>=l&&a[id].x<=r)
{
if(--v[s[a[id].x]]==0)
{
res--;
}
if(++v[a[id].y]==1)
{
res++;
}
}
swap(a[id].y,s[a[id].x]);
}
int main()
{
scanf("%d%d",&n,&m);
block=pow(n,2/3);
for(int i=1;i<=n;i++)
{
scanf("%d",&s[i]);
}
for(int i=1;i<=m;i++)
{
scanf("%s",ch);
if(ch[0]=='Q')
{
cnt++;
scanf("%d%d",&q[cnt].l,&q[cnt].r);
q[cnt].num=cnt,q[cnt].tim=num;
}
else
{
num++;
scanf("%d%d",&a[num].x,&a[num].y);
}
}
sort(q+1,q+1+cnt,cmp);
int L=1,R=0,now=0;
for(int i=1;i<=cnt;i++)
{
while(L>q[i].l)
{
L--;
ins(s[L]);
}
while(R<q[i].r)
{
R++;
ins(s[R]);
}
while(L<q[i].l)
{
del(s[L]);
L++;
}
while(R>q[i].r)
{
del(s[R]);
R--;
}
while(now<q[i].tim)
{
now++;
change(q[i].l,q[i].r,now);
}
while(now>q[i].tim)
{
change(q[i].l,q[i].r,now);
now--;
}
ans[q[i].num]=res;
}
for(int i=1;i<=cnt;i++)
{
printf("%d\n",ans[i]);
}
}
对于每个点,记录这个点的颜色上一次出现的位置作为这个点的点权,每次查询l,r就相当于查询l到r之间点权小于l的点有多少个。实现起来直接用树套树就好了,外层用线段树维护序列区间信息,内层平衡树维护区间排名,每次只要找线段树对应点的平衡树内l的排名就好了。但修改比较麻烦,每次修改x点需要改变x修改前颜色中x的后继的前驱、x的前驱和修改后颜色中x的后继的前驱。对于每种颜色开一个set来维护前驱后继,每次修改时对应修改就好了,但要注意判断x是否有前驱和后继。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int x,y;
int n,m;
int tot;
int opt;
char ch[3];
int a[50010];
int v[2000010];
int w[2000010];
int t[2000010];
int l[500010];
int r[500010];
int ls[2000010];
int rs[2000010];
int pre[50010];
int suf[50010];
int size[2000010];
int root[500010];
map<int,int>b;
set<int>s[1000010];
set<int>::iterator it;
int inbuild(int k)
{
tot++;
t[tot]=rand();
v[tot]=k;
w[tot]=1;
size[tot]=1;
ls[tot]=rs[tot]=0;
return tot;
}
void updata(int rt)
{
size[rt]=size[ls[rt]]+size[rs[rt]]+w[rt];
}
void lturn(int &rt)
{
int t=rs[rt];
rs[rt]=ls[t];
ls[t]=rt;
updata(rt);
updata(t);
rt=t;
}
void rturn(int &rt)
{
int t=ls[rt];
ls[rt]=rs[t];
rs[t]=rt;
updata(rt);
updata(t);
rt=t;
}
void insert(int &rt,int k)
{
if(!rt)
{
rt=inbuild(k);
return ;
}
if(v[rt]==k)
{
w[rt]++;
}
else
{
if(k<v[rt])
{
insert(ls[rt],k);
if(t[ls[rt]]<t[rt])
{
rturn(rt);
}
}
else
{
insert(rs[rt],k);
if(t[rs[rt]]<t[rt])
{
lturn(rt);
}
}
}
updata(rt);
}
void del(int &rt,int k)
{
if(v[rt]<k)
{
del(rs[rt],k);
}
else if(v[rt]>k)
{
del(ls[rt],k);
}
else
{
if(w[rt]>1)
{
w[rt]--;
}
else
{
if(!ls[rt]||!rs[rt])
{
rt=ls[rt]+rs[rt];
}
else
{
if(t[ls[rt]]<t[rs[rt]])
{
rturn(rt);
del(rs[rt],k);
}
else
{
lturn(rt);
del(ls[rt],k);
}
}
}
}
if(rt)
{
updata(rt);
}
}
int inrank(int rt,int k)
{
if(!rt)
{
return 0;
}
if(v[rt]==k)
{
return size[ls[rt]];
}
else if(v[rt]<k)
{
return size[ls[rt]]+w[rt]+inrank(rs[rt],k);
}
else
{
return inrank(ls[rt],k);
}
}
void outbuild(int rt,int L,int R)
{
l[rt]=L;
r[rt]=R;
for(int i=L;i<=R;i++)
{
insert(root[rt],pre[i]);
}
if(L!=R)
{
int mid=(L+R)>>1;
outbuild(rt<<1,L,mid);
outbuild(rt<<1|1,mid+1,R);
}
}
void change(int rt,int x,int y)
{
del(root[rt],pre[x]);
insert(root[rt],y);
if(l[rt]!=r[rt])
{
int mid=(l[rt]+r[rt])>>1;
if(x<=mid)
{
change(rt<<1,x,y);
}
else
{
change(rt<<1|1,x,y);
}
}
}
int outrank(int rt,int L,int R,int k)
{
if(L<=l[rt]&&r[rt]<=R)
{
return inrank(root[rt],k);
}
int mid=(l[rt]+r[rt])>>1;
if(R<=mid)
{
return outrank(rt<<1,L,R,k);
}
else if(L>mid)
{
return outrank(rt<<1|1,L,R,k);
}
return outrank(rt<<1,L,R,k)+outrank(rt<<1|1,L,R,k);
}
int main()
{
srand(12378);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
pre[i]=b[a[i]];
suf[b[a[i]]]=i;
b[a[i]]=i;
s[a[i]].insert(i);
}
for(int i=1;i<=n;i++)
{
if(!suf[i])
{
suf[i]=n+1;
}
}
outbuild(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%s",ch);
if(ch[0]=='R')
{
scanf("%d%d",&x,&y);
if(a[x]==y)
{
continue;
}
if(pre[x])
{
suf[pre[x]]=suf[x];
}
if(suf[x]!=n+1)
{
change(1,suf[x],pre[x]);
pre[suf[x]]=pre[x];
}
s[a[x]].erase(x);
a[x]=y;
s[a[x]].insert(x);
it=s[a[x]].lower_bound(x);
if(it!=s[a[x]].begin())
{
it--;
suf[(*it)]=x;
change(1,x,(*it));
pre[x]=(*it);
it++;
}
else
{
change(1,x,0);
pre[x]=0;
}
if(++it!=s[a[x]].end())
{
suf[x]=(*it);
change(1,(*it),x);
pre[(*it)]=x;
}
else
{
suf[x]=n+1;
}
}
else
{
scanf("%d%d",&x,&y);
printf("%d\n",outrank(1,x,y,x));
}
}
}

BZOJ2120&2453数颜色——线段树套平衡树(treap)+set/带修改莫队的更多相关文章

  1. 树套树Day1线段树套平衡树bzoj3196

    您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查 ...

  2. 【BZOJ-3196】二逼平衡树 线段树 + Splay (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2271  Solved: 935[Submit][Stat ...

  3. BZOJ3196二逼平衡树——线段树套平衡树(treap)

    此为平衡树系列最后一道:二逼平衡树您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询 ...

  4. bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

    3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description ...

  5. bzoj 2120 线段树套平衡树

    先吐下槽,改了快一个小时,最后发现是SBT的delete写错了,顿时就有想死的心..... 首先对于这道题,我们应该先做一下他的小问题,bzoj1878,虽然和这道题几乎一点关系没有, 但是能给我们一 ...

  6. P3380 【模板】二逼平衡树(树套树) 线段树套平衡树

    \(\color{#0066ff}{ 题目描述 }\) 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上 ...

  7. BZOJ3196 二逼平衡树 【线段树套平衡树】

    题目 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱 ...

  8. 浅谈树套树(线段树套平衡树)&学习笔记

    0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...

  9. CF 19D - Points 线段树套平衡树

    题目在这: 给出三种操作: 1.增加点(x,y) 2.删除点(x,y) 3.询问在点(x,y)右上方的点,如果有相同,输出最左边的,如果还有相同,输出最低的那个点 分析: 线段树套平衡树. 我们先离散 ...

随机推荐

  1. [03] JSP指令

    1.概述 JSP指令用于"转换阶段"提供整个JSP页面的相关信息,影响由JSP页面生成的Servlet的整体结构.指令不会产生任何的输出到当前的输出流中. 指令的基本语法为: &l ...

  2. Vue-接口跨域请求调试proxyTable

    在项目开发的时候,接口联调的时候一般都是同域名下,且不存在跨域的情况下进行接口联调,但是当我们现在使用vue-cli进行项目打包的时候,我们在本地启动服务器后,比如本地开发服务下是 http://lo ...

  3. 如何实现.net程序的进程注入

    原文:如何实现.net程序的进程注入   如何实现.net程序的进程注入                                   周银辉 进程注入比较常见,比如用IDE调试程序以及一些Sp ...

  4. 从零开始搭建属于你的React/redux/webpack脚手架

    大家好,我是苏南,今天要给大家分享的是<<我的react入门到放弃之路>>,当然,也不是真的放弃啦--哈哈,这篇博客原本是从17年初写的,一直没有在csdn发布,希望今天不会太 ...

  5. element-ui + vue + node.js 与 服务器 Python 应用的跨域问题

    跨越问题解决的两种办法: 1. 在 config => index.js 中配置 proxyTable 代理: proxyTable: { '/charts': { target: 'http: ...

  6. PyCharm Tips 常用操作帮助

    以下内容转自 http://www.2cto.com/os/201410/341542.html --------------------------------------------------- ...

  7. 软件工程APP进度更新

    对原有的界面进行了美化,同时加进了背景音乐,并且优化了算法部分的代码 正在一步一步跟进中 顺带附上上一次组员帮我发的进度地址:http://www.cnblogs.com/case1/p/498192 ...

  8. Practice3 阅读《构建之法》1-5章

    第一章:概论 本章主要是讲了软件工程的基本概念,软件工程的最终目标是创造“足够好”的软件. 提出问题:什么是BUG?(出自1.2.5节) 答:就我个人而言,在许多游戏中也有许多的BUG,BUG这一词在 ...

  9. spring mvc的工作原理

    该文转载自:http://blog.csdn.net/u012191627/article/details/41943393 SpringMVC框架介绍 1) spring MVC属于SpringFr ...

  10. Maven相关问题解决.docx

    1. 问题 2. 原因 出现.lastUpdated结尾的文件的原因:由于网络原因没有将Maven的依赖下载完整,导致. 解决方案: 1.删除所有以.lastUpdate结尾的文件 a)1.切换到ma ...