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. java基础之XML

    目录 java基础之XML 1. XML解析概述 2. DOM4J介绍 2.1 常用包 2.2 内置元素 2.2 Element类 2.3 Attribute类 2.4 常用操作 3. 代码演示 3. ...

  2. JqGrid: Add,Edit,Del in asp.net

    https://github.com/1rosehip/jplist https://github.com/free-jqgrid/jqGrid https://plugins.jquery.com/ ...

  3. sql server: left join 重复数据

    ---涂聚文 2017-9-28 SELECT VipExamMailProjectId,VipExamMailStaffID FROM VipExamMailRecord WHERE VipExam ...

  4. IE9获取file控件的本地文件路径

    最近发现,在IE9下,公司网站的本地图片预览都无法正常显示,经过测试发现,原因在于IE9下无法获取file控件的文件路径. 以前的代码如下: var strPic = fileImg.value; i ...

  5. VUE CLI 3.0 项目引入 Mock.js

    mockjs 官网:http://mockjs.com/ 之前没有使用过 mockjs 的同学,请参考官网文档,数据生成规则和方法的调用都有详细说明. 一.通过npm安装依赖包 1. 进入到项目目录, ...

  6. 解决如下问题:You are using pip version 8.1.1, however version 18.0 is available. You should consider upgrading via the 'pip install --upgrade pip' command.

    问题描述: 今天想学习一下TUM数据集RGBD-Benchmark工具的使用,利用python进行相关操作时,缺少一个第三方模块,于是打算用pip进行安装,便出现如下图所示的问题. 解决办法: 执行如 ...

  7. 我的Java之旅 第一课 开发环境准备

    1.JDK JDK(Java Development Kit) 是 Java 语言的软件开发工具包(SDK). SE(J2SE),standard edition,标准版,是我们通常用的一个版本,从J ...

  8. 安卓开发_浅谈主配置文件(AndroidManifest.xml)

    AndroidManifest.xml本质:是整个应用的主配置清单文件包含:该应用的包名,版本号,组件,权限等信息作用:记录该应用的相关的配置信息 一.常用标签(1).全局篇(包名,版本信息)(2). ...

  9. (其他)SQL注入(转)

    转自维基百科: SQL注入是一种代码注入技术,用于攻击数据驱动的应用程序,在这种应用程序中,恶意的SQL语句被插入输入字段中执行(例如将数据库内容转储给攻击者).[1] SQL注入必须利用应用程序软件 ...

  10. BD是什么角色

    BD是什么角色? 在一般创业公司里面,有了产品接下来就是运营了,而运营中很重要的一点就是BD,也就是所谓商务拓展了,俗一点说就是生意的合作拓展 https://www.jianshu.com/p/7d ...