Description

给定长度为$n$的数组, 定义数字$X$在$[l,r]$内的值为数字$X$在$[l,r]$内最后一次出现位置的下标减去第一次出现位置的下标
给定$m$次询问, 每次询问有三个整数$a,b,c$询问规则如下:
当$a=1$时, 将数组内第$b$个元素更改为$c$
当$a=2$时, 求区间$[b,c]$所有数字的值的和

Input

第一行两个整数$n$,$m$
第二行$n$个整数, 表示数组
第$3$到$3+m$行, 每行三个整数, 表示每次询问。

Output

对于每次$a=2$的询问, 输出一个整数表示答案

Sample Input1

7 6
1 2 3 1 3 2 1
2 3 7
2 1 3
1 7 2
1 3 2
2 1 6
2 5 7

Sample Output1

5
0
7
1

Sample Input2

7 5
1 3 2 1 4 2 3
1 1 4
2 2 3
1 1 7
2 4 5
1 1 7

Sample Output2

0
0

Solution

设初始每个位置对应点$(i,pre[i])$,权值为$i-pre[i]$。可以把初始位置上的点看成矩形单点加操作。
$pre[i]$为$i$这个位置的数上一次出现的位置,若没有则为$0$。
那么查询区间$[L,R]$就相当于查询左下$(L,L)$右上$(R,R)$的矩形的权值和(写写画画可能比较容易明白),可以$CDQ$。
考虑一次修改会影响什么?设$i$位置把$x$修改成$y$,只会影响和$i$相邻的$x$和$y$,这个可以用$set$维护,然后看成若干矩形单点加操作。
那么就可以写一个只有单点加和矩形求和的$CDQ$分治了。

Code

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#define N (700009)
#define LL long long
using namespace std; struct Que{int x,y,opt,v;}Q[N],tmp[N];
int n,m,cnt,q_num;
int a[N],b[N],pre[N];
LL c[N],ans[N];
set<int>S[N];
set<int>::iterator it; inline int read()
{
int x=,w=; char c=getchar();
while (c<'' || c>'') {if (c=='-') w=-; c=getchar();}
while (c>='' && c<='') x=x*+c-'', c=getchar();
return x*w;
} void Update(int x,int k)
{
for (; x<=n+; x+=(x&-x)) c[x]+=k;
} LL Query(int x)
{
LL ans=;
for (; x; x-=(x&-x)) ans+=c[x];
return ans;
} void CDQ(int l,int r)
{
if (l==r) return;
int mid=(l+r)>>;
CDQ(l,mid); CDQ(mid+,r);
int i=l,j=mid+,k=l-;
while (i<=mid || j<=r)
if (j>r || i<=mid && (Q[i].x<Q[j].x || Q[i].x==Q[j].x && Q[i].opt<Q[j].opt))
{
if (Q[i].opt==) Update(Q[i].y,Q[i].v);
tmp[++k]=Q[i]; ++i;
}
else
{
if (Q[j].opt==)
{
if (Q[j].v>) ans[Q[j].v]+=Query(Q[j].y);
else ans[-Q[j].v]-=Query(Q[j].y);
}
tmp[++k]=Q[j]; ++j;
}
for (int i=l; i<=mid; ++i)
if (Q[i].opt==) Update(Q[i].y,-Q[i].v);
for (int i=l; i<=r; ++i) Q[i]=tmp[i];
}
int main()
{
n=read(); m=read();
for (int i=; i<=n; ++i)
{
a[i]=read(); pre[i]=b[a[i]]; b[a[i]]=i;
S[a[i]].insert(i); Q[++q_num]=(Que){i,pre[i],,i-pre[i]};
}
for (int i=; i<=m; ++i)
{
int opt=read(),x=read(),y=read();
if (opt==)
{
int p1=,n1=;//前驱 后继
it=S[a[x]].find(x);
if (it!=S[a[x]].begin()) --it, p1=*it, ++it;
if ((++it)!=S[a[x]].end()) n1=*it; --it;
S[a[x]].erase(*it); Q[++q_num]=(Que){x,pre[x],,pre[x]-x};
if (n1)
{
Q[++q_num]=(Que){n1,pre[n1],,pre[n1]-n1};
pre[n1]=p1;
Q[++q_num]=(Que){n1,pre[n1],,n1-pre[n1]};
} int p2=,n2=;
a[x]=y; S[a[x]].insert(x);
it=S[a[x]].find(x);
if (it!=S[a[x]].begin()) --it, p2=*it, ++it;
if ((++it)!=S[a[x]].end()) n2=*it; --it;
pre[x]=p2; Q[++q_num]=(Que){x,pre[x],,x-pre[x]};
if (n2)
{
Q[++q_num]=(Que){n2,pre[n2],,pre[n2]-n2};
pre[n2]=x;
Q[++q_num]=(Que){n2,pre[n2],,n2-pre[n2]};
}
}
else
{
++cnt;
Q[++q_num]=(Que){x-,x-,,cnt};
Q[++q_num]=(Que){y,y,,cnt};
Q[++q_num]=(Que){x-,y,,-cnt};
Q[++q_num]=(Que){y,x-,,-cnt};
}
}
for (int i=; i<=q_num; ++i) Q[i].x++, Q[i].y++;
CDQ(,q_num);
for (int i=; i<=cnt; ++i) printf("%lld\n",ans[i]);
}

CF848C:Goodbye Souvenir(CDQ分治)的更多相关文章

  1. Codeforces 848C Goodbye Souvenir [CDQ分治,二维数点]

    洛谷 Codeforces 这题我写了四种做法-- 思路 不管做法怎样,思路都是一样的. 好吧,其实不一样,有细微的差别. 第一种 考虑位置\(x\)对区间\([l,r]\)有\(\pm x\)的贡献 ...

  2. Codeforces 848C Goodbye Souvenir(CDQ 分治)

    题面传送门 考虑记录每个点的前驱 \(pre_x\),显然答案为 \(\sum\limits_{i=l}^{r} i-pre_i (pre_i \geq l)\) 我们建立一个平面直角坐标系,\(x\ ...

  3. Codeforces 848C (cdq分治)

    Codeforces 848C Goodbye Souvenir Problem : 给一个长度为n的序列,有q个询问.一种询问是修改某个位置的数,另一种询问是询问一段区间,对于每一种值出现的最右端点 ...

  4. 【教程】简易CDQ分治教程&学习笔记

    前言 辣鸡蒟蒻__stdcall终于会CDQ分治啦!       CDQ分治是我们处理各类问题的重要武器.它的优势在于可以顶替复杂的高级数据结构,而且常数比较小:缺点在于必须离线操作. CDQ分治的基 ...

  5. BZOJ 2683 简单题 ——CDQ分治

    [题目分析] 感觉CDQ分治和整体二分有着很本质的区别. 为什么还有许多人把他们放在一起,也许是因为代码很像吧. CDQ分治最重要的是加入了时间对答案的影响,x,y,t三个条件. 排序解决了x ,分治 ...

  6. HDU5618 & CDQ分治

    Description: 三维数点 Solution: 第一道cdq分治...感觉还是很显然的虽然题目不能再傻逼了... Code: /*=============================== ...

  7. 初识CDQ分治

    [BZOJ 1176:单点修改,查询子矩阵和]: 1176: [Balkan2007]Mokia Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 200 ...

  8. HDU5322 Hope(DP + CDQ分治 + NTT)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5322 Description Hope is a good thing, which can ...

  9. BZOJ4170 极光(CDQ分治 或 树套树)

    传送门 BZOJ上的题目没有题面-- [样例输入] 3 5 2 4 3 Query 2 2 Modify 1 3 Query 2 2 Modify 1 2 Query 1 1 [样例输出] 2 3 3 ...

随机推荐

  1. Windows环境使用Nexus-3.x搭建Maven私服

    [前言] 本文主要讲解在Wiindows环境下搭建最新出的Nexus 3.x私服. 1.搭建私服的必要性 一般情况下,各个公司的开发团队为了提高开发效率,都会使用项目构建工具进行开发.常见的构建工具有 ...

  2. Hibernate session中的createCriteria方法

    在应用中获取session对象: Session session=  HibernateUtil.getSession(); List list=session.createCriteria(Mete ...

  3. Laravel 中使用支付宝、银联支付、微信支付进行支付

    Laravel Packages 为 Laravel 提供了强大的扩展功能,为从 1 到 n 提供无限可能,这其中就包括支付, Laravel 官方提供的 Cashier 包集成对 Stripe 的支 ...

  4. 【Java深入研究】4、fail-fast机制

    在JDK的Collection中我们时常会看到类似于这样的话: 例如,ArrayList: 注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证.快速失 ...

  5. 【Redis】5、Redis事务处理

    MULTI .EXEC .DISCARD 和WATCH 是 Redis 事务的基础 1.MULTI  命令用于开启一个事务,它总是返回 OK .MULTI 执行之后,客户端可以继续向服务器发送任意多条 ...

  6. FormData对象的使用

    一.概述 FormData类型是XMLHttpRequest 2级定义的,它是为序列化表以及创建与表单格式相同的数据提供便利. 作用:1.利用一些键值对来模拟一系列表单控件:即将form中的所有表单元 ...

  7. 在EXT框架中,使用JS文件设置UEditor文本框,出现新增内容很多,页面变型,不出现滚动条,导致无法进行操作。

    找到UEditor的配置文件:ueditor.config.js(这是我的项目的UEditor的配置文件名) 找到参数设置 autoHeightEnabled 是否自动增长参数,默认为TRUE 当默认 ...

  8. JqGrid: paging int asp.net

    https://www.codeproject.com/Articles/1118363/GridView-with-Server-Side-Filtering-Sorting-and-Pa http ...

  9. css选择器:基本选择器

    基本选择器 1.通用元素选择器 *表示应用到所有的标签. *{ padding:0px; margin:0px; } 2.元素/标签选择器 匹配所有p标签的元素 p{ color:red; backg ...

  10. JavaScript原型与原型链,原型的实际应用

    原型链是js面向对象的基础,非常重要. 一,创建对象的几种方法: 1,字面量 var o1 = { name:'o1' }; 2,构造函数 var M = function(name){ this.n ...