题目

有n个数编号从0→n-1,两种操作:

Q L R:询问编号为L→R-1的数中共有多少种不同的数

M X Y:将编号为X的数改为Y

共有m个操作

分析

既然是单点修改,查询,我们考虑一下分块。

首先,定义\(next_{i}\)表示,在\(i\)之后的第一个与编号为\(i\)的数相同的数的位置。

接着,我们把\(i\)向\(next_{i}\)连一条边。

那么就会发现,当把边处理好后,查询操作就迎刃而解了;

查询操作

假设现在要查询\([x,y]\),



其中next,以及它们的连边的情况是:



发现,编号为\(a\)的数和编号为\(next_a\)的数的数以及编号为\(b\)的数和编号为\(next_b\)的数的数都重复了。

那么就要减去重复的,

而编号为\(next_c\)的数并不在\([x,y]\),所以并不需要减去。

我们得出一个结论:\(\color{red}{当next_i<=y时,编号为i的数一定有重复,所以我们就只记录最后一个,即next_i>y的那一个}\)

那如何处理呢?

对于不是整块的部分,暴力处理。时间复杂度\(O(2\sqrt{n})\)。

对于整块的部分,把整块按\(next_{i}\)排序,二分求答案。

修改操作

我们再定义\(last_{i}\)表示,在\(i\)之前的第一个与编号为\(i\)的数相同的数的位置。

再把\(i\)向\(last_{i}\)连一条边;

假设我们修改位置x,



那么,因为x修改成别的值,所以\(next[last[x]]\)就要就修成\(next[x]\),\(last[next[x]]\)就要就改成\(last[x]\)

接着,发现,这样\(next[last[x]]\)改变了,于是,重新把\(last[x]\)所在的块排序。

然后,就要处理位置x新的\(last和next\)。

假设x所在的块的开头和结尾是s和t。



处理\(last\):

我们先暴力查看x-1~s的位置中是否出现过y,如果有,修改\(last[x]\)以及\(next[last[x]]\)。

否则查看前面的块,

再定义\(sum[i][j]\)表示,在第i个块中,j这个数出现过多少次。

找到了,就修改就可以了。

处理\(next\)类似。

记住,如果某个位置的\(next\)修改了,就将这个位置所在的块排个序。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=50005;
using namespace std;
int a[N*2],n,m,ans,next[N*2],last[N*2],part[N][2],size,as[N*2],pos[N*2],stead[1000005],sum[250][N*2],tot,color[N*2],num;
bool cmp(int x,int y)
{
return next[x]<next[y];
}
int preblock()
{
size=sqrt(n);
for(int i=1;i<=n;i+=size)
{
part[++tot][0]=i;
if(i+size-1>n)
part[tot][1]=n;
else
part[tot][1]=i+size-1;
}
for(int i=1;i<=tot;i++)
for(int j=part[i][0];j<=part[i][1];j++)
{
sum[i][stead[a[j]]]++;
pos[j]=i;
}
}
int prenexus()
{
memset(color,0,sizeof(color));
for(int i=0;i<=n;i++)
{
last[i]=color[stead[a[i]]];
color[stead[a[i]]]=i;
}
memset(color,0,sizeof(color));
for(int i=n;i>=0;i--)
{
next[i]=color[stead[a[i]]];
if(!next[i])
next[i]=maxlongint;
color[stead[a[i]]]=i;
}
}
int so(int x)
{
sort(as+part[x][0],as+part[x][1]+1,cmp);
}
int fs(int x,int y,int y1)
{
for(int i=x;i<=y;i++)
if(next[i]>y1)
ans++;
}
int zt(int x,int y,int y1)
{
int ll=x-1,rr=y;
while(ll<rr-1)
{
int mid=(ll+rr)/2;
if(next[as[mid]]<=y1) ll=mid;
else rr=mid;
}
int q=0;
if(next[as[rr]]<=y1) q=rr;
else q=ll;
ans+=y-x+1-(q-x+1);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(!stead[a[i]])
{
stead[a[i]]=++num;
}
}
preblock();
prenexus();
for(int i=1;i<=n;i++) as[i]=i;
for(int i=1;i<=tot;i++) so(i);
for(int k=1;k<=m;k++)
{
char c=getchar();
while(c!='Q' && c!='M') c=getchar();
int x,y;
scanf(" %d %d",&x,&y);
x+=1;
if(c=='Q')
{
ans=0;
int l=pos[x],r=pos[y];
if(l==r)
{
for(int i=x;i<=y;i++)
if(next[i]>y) ans++;
printf("%d\n",ans);
continue;
}
if(x>part[l][0])
{
for(int i=x;i<=part[l][1];i++)
if(next[i]>y) ans++;
l++;
}
if(y<part[r][1])
{
for(int i=part[r][0];i<=y;i++)
if(next[i]>y) ans++;
r--;
}
for(int i=l;i<=r;i++)
zt(part[i][0],part[i][1],y);
printf("%d\n",ans);
}
else
{
bool q=true;
if(!stead[y])
{
stead[y]=++num;
q=false;
}
next[last[x]]=next[x];
if(next[x]!=maxlongint)
last[next[x]]=last[x];
sum[pos[x]][stead[a[x]]]--;
sum[pos[x]][stead[y]]++;
so(pos[last[x]]);
a[x]=y;
if(!q)
{
last[x]=0;
next[x]=maxlongint;
}
else
{
int p=0,p1=0;
for(int i=x-1;i>=part[pos[x]][0];i--)
if(a[i]==y)
{
p=i;
break;
}
if(!p)
{
for(int i=pos[x]-1;i>=1;i--)
{
if(sum[i][stead[y]])
{
for(int j=part[i][1];j>=part[i][0];j--)
if(a[j]==y)
{
p=j;
break;
}
break;
}
}
}
if(p)
{
last[x]=p;
next[p]=x;
so(pos[p]);
}
else
last[x]=0;
for(int i=x+1;i<=part[pos[x]][1];i++)
if(a[i]==y)
{
p1=i;
break;
}
if(!p1)
{
for(int i=pos[x]+1;i<=tot;i++)
{
if(sum[i][stead[y]])
{
for(int j=part[i][0];j<=part[i][1];j++)
if(a[j]==y)
{
p1=j;
break;
}
break;
}
}
}
if(p1)
{
next[x]=p1;
last[p1]=x;
so(pos[x]);
}
else
next[x]=maxlongint;
}
so(pos[x]);
}
}
}

Dynamic len的更多相关文章

  1. Uva 3767 Dynamic len(set(a[L:R])) 树套树

    Dynamic len(set(a[L:R])) Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://uva.onlinejudge.org/in ...

  2. UVA 12345 Dynamic len(带修莫队)

    Dynamic len [题目链接]Dynamic len [题目类型]带修莫队 &题解: 莫队可以单点更改,只要再多加一维,代表查询次数,排序的时候3个关键字. 之后循环离线的时候,先暴力时 ...

  3. 【题解】Luogu UVA12345 Dynamic len(set(a[L:R]))

    原题传送门 这题要用动态莫队,我博客里有介绍 这道题和luogu P1903 [国家集训队]数颜色 / 维护队列差不多,解法就在上面那篇博客里qaq 主要的问题是如何排序? 排序有三个关键字: 1.左 ...

  4. (待修莫队 没过! 抽空在检查)Dynamic len(set(a[L:R])) UVA - 12345

    #include <iostream> #include <cstdio> #include <sstream> #include <cstring> ...

  5. Dynamic len(set(a[L:R])) UVA - 12345(这么过分一定要写博客)

    给出一个有n个元素的数组,有以下两种操作:Q x y,求出区间[x,y)内不同元素的个数, M x y,把第x个元素的值修改为y.注意题目中的下标是从0开始的 这题超级超级坑 妈的一个水题找了几个小时 ...

  6. UVA 12345 Dynamic len(set(a[LR]))

    题意:询问区间唯一元素个数,单点修改. 分析: 借助Unique snowflakes, Can you answer these queries II的思想,唯一性可以借助元素上一次出现的位置来判断 ...

  7. [UVa12345] Dynamic len (带 修 )

    题意:有n个数编号从0→n-1,两种操作:            Q L R:询问编号为L→R-1的数中共有多少种不同的数             M X Y:将编号为X的数改为Y           ...

  8. UESTC-1259 昊昊爱运动 II

    昊昊爱运动 II Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)     昊昊喜 ...

  9. UVA12345 (带修改的莫队)

    UVA12345 Dynamic len Problem : 给一个序列,每次询问一个区间里面的数字种类数量,或者修改某一个位置的值. Solution : 第一关键字分块排序左端点,第二关键字分块排 ...

随机推荐

  1. Linux_OpenSSH远程连接

    目录 目录 SSH server SSH服务属性 SSH协议执行原理 SSH连接方式 ssh Commands scp commands sftp commands SSH在生产环境中的使用 系统间备 ...

  2. 四:flask-URL两种传参方式(路径传参和get传参)

    新建一个视图 第一种:路径传参:url/参数:<参数名>,然后再视图函数中接收参数 也可以指定数据类型 string:默认使用此数据类型,接收没有任何斜杠"\/"的文本 ...

  3. kubernets监控

    Weave Scope 容器地图   创建 Kubernetes 集群并部署容器化应用只是第一步.一旦集群运行起来,我们需要确保一起正常,所有必要组件就位并各司其职,有足够的资源满足应用的需求.Kub ...

  4. oracle-SYSTEM表空间的备份与恢复

    oracle-SYSTEM表空间的备份与恢复 这一篇在介绍备份及恢复数据文件的方法时,以备份和重做日志(包括归档日志和在线日志)没有丢失为前提 所谓关键数据文件:system表空间的数据文件与参数un ...

  5. 工具类分享之获取Request/Response工具类《RequestContextHolderUtil》

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/aiyaya_/article/details/78975893前言在开发spring web项目时, ...

  6. 动态SQL之模糊查询

    模糊查询学习了三种: DAO层 // 可以使用 List<User> wherelike01(String user_name); // 忘记 List<User> where ...

  7. 为什么存储过程比sql语句效率高?

    存储过程经过预编译处理 而SQL查询没有 SQL语句需要先被数据库引擎处理成低级的指令 然后才执行 -------------------------------------------------- ...

  8. MySQL-快速入门(6)连接查询、子查询、正则表达式查询、数据的插入删除更新

    1.内连接查询:inner join ... on 只有满足条件的记录才能够出现在结果关系中,即完全相等.自连接查询是一种特殊的内连接查询. 2.外连接查询: 1>左外连接 / 左连接:返回包括 ...

  9. mysql5.7 修改用户密码

    修改vi /etc/my.cnf,增加skip-grant-tables可以免密码登录mysql use mysql ; update user set authentication_string=P ...

  10. C++中的字符串类

    1,本文分析 C++ 中的字符串,C 语言中的字符串利用的是 C 语言中的字符数组,  在 C 语言中没有真正意义上的字符串,利用了字符数组表示了字符串,最初设  计 C 语言仅仅是为了开发 Unix ...