题面传送门

考虑记录每个点的前驱 \(pre_x\),显然答案为 \(\sum\limits_{i=l}^{r} i-pre_i (pre_i \geq l)\)

我们建立一个平面直角坐标系,\(x\) 轴表示下标 \(i\),\(y\) 轴表示前驱 \(pre_i\),点权为 \(i-pre_i\)。

每次询问以 \((l,l)\) 为左下角,\((r,n)\) 为右下角的矩形中所有点的权值和。

至于修改操作,就是撤销上次操作的贡献,加入新的贡献。

至此,我们就把问题转化为单点加,矩形和的问题,再加上有时间轴,三维偏序,故可用 CDQ 分治维护。

/*
Contest: -
Problem: Codeforces 848C
Author: tzc_wk
Time: 2020.7.17
*/
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define fillsmall(a) memset(a,0xcf,sizeof(a))
#define y1 y1010101010101
#define y0 y0101010101010
#define int long long
typedef pair<int,int> pii;
inline int read(){
int x=0,neg=1;char c=getchar();
while(!isdigit(c)){
if(c=='-') neg=-1;
c=getchar();
}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x*neg;
}
const int INF=1e9;
int n=read(),m=read(),k=0,ans[1000005],a[100005];
struct data{
int t,p2,p1,p3;
} p[1000005],tmp[1000005];
set<int> st[100005];
struct BIT{
int bit[2000005];
inline void add(int x,int v){
x++;
for(int i=x;i<=n+1;i+=(i&(-i))) bit[i]+=v;
}
inline int query(int x){
x++;
int sum=0;
for(int i=x;i;i-=(i&(-i))) sum+=bit[i];
return sum;
}
} t;
inline void merge(int l,int r,int mid){
int p1=l,p2=mid+1;
for(int i=l;i<=r;i++){
if(p1<=mid&&(p2>r||p[p1].p2<p[p2].p2))
tmp[i]=p[p1++];
else
tmp[i]=p[p2++];
}
for(int i=l;i<=r;i++){
p[i]=tmp[i];
}
}
inline void CDQ(int l,int r){
if(l==r) return;
int mid=(l+r)>>1;
CDQ(l,mid);CDQ(mid+1,r);
// printf("%d %d\n",l,r);
int cur=l;
for(int i=mid+1;i<=r;i++){
if(p[i].p3!=-INF) continue;
while(cur<=mid&&p[cur].p2<=p[i].p2){
if(p[cur].p3!=-INF) t.add(p[cur].p1,p[cur].p3);
cur++;
}
ans[p[i].t]+=t.query(n)-t.query(p[i].p1-1);
}
fz(i,l,cur-1) if(p[i].p3!=-INF) t.add(p[i].p1,-p[i].p3);
merge(l,r,mid);
}
signed main(){
fz(i,1,n) a[i]=read();
fz(i,1,n) st[i].insert(0);
fz(i,1,n){
p[++k]={k,i,*st[a[i]].rbegin(),i-*st[a[i]].rbegin()};
st[a[i]].insert(i);
}
fz(i,1,n) st[i].insert(n+1);
fill1(ans);
fz(i,1,m){
int op=read(),x=read(),y=read();
if(op==1){
set<int>::iterator pre=--st[a[x]].lower_bound(x);
set<int>::iterator nxt=st[a[x]].upper_bound(x);
p[++k]={k,*nxt,x,-((*nxt)-x)};
p[++k]={k,x,*pre,-(x-(*pre))};
p[++k]={k,*nxt,*pre,(*nxt)-(*pre)};
st[a[x]].erase(x);
a[x]=y;
pre=--st[a[x]].lower_bound(x);
nxt=st[a[x]].upper_bound(x);
p[++k]={k,*nxt,x,((*nxt)-x)};
p[++k]={k,x,*pre,(x-(*pre))};
p[++k]={k,*nxt,*pre,-((*nxt)-(*pre))};
st[a[x]].insert(x);
}
else{
p[++k]={k,y,x,-INF};
ans[k]=0;
}
}
// fz(i,1,k){
// printf("%d %d %d %d\n",p[i].t,p[i].p1,p[i].p2,p[i].p3);
// }
// puts("-1");
CDQ(1,k);
fz(i,1,k) if(ans[i]!=-1) printf("%lld\n",ans[i]);
return 0;
}

Codeforces 848C Goodbye Souvenir(CDQ 分治)的更多相关文章

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

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

  2. [Codeforces]848C - Goodbye Souvenir

    题目大意:n个数字,m次操作,支持修改一个数字和查询一个区间内每种数字最大出现位置减最小出现位置的和.(n,m<=100,000) 做法:把每个数字表示成二维平面上的点,第一维是在数组中的位置, ...

  3. CF848C:Goodbye Souvenir(CDQ分治)

    Description 给定长度为$n$的数组, 定义数字$X$在$[l,r]$内的值为数字$X$在$[l,r]$内最后一次出现位置的下标减去第一次出现位置的下标给定$m$次询问, 每次询问有三个整数 ...

  4. [Codeforces]849E Goodbye Souvenir

    又是一道比较新的模板题吧,即使是在Codeforces上小C还是贴了出来. Description 给定一个长度为n的序列a1~an,每个元素代表一种颜色.m次操作,每次操作为两种中的一种: 1 p ...

  5. Codeforces 1045G AI robots [CDQ分治]

    洛谷 Codeforces 简单的CDQ分治题. 由于对话要求互相看见,无法简单地用树套树切掉,考虑CDQ分治. 按视野从大到小排序,这样只要右边能看见左边就可以保证互相看见. 发现\(K\)固定,那 ...

  6. Codeforces 526F Pudding Monsters - CDQ分治 - 桶排序

    In this problem you will meet the simplified model of game Pudding Monsters. An important process in ...

  7. Codeforces 848C (cdq分治)

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

  8. 【Codeforces 848C】Goodbye Souvenir

    Codeforces 848 C 题意:给\(n\)个数,\(m\)个询问,每一个询问有以下类型: 1 p x:将第p位改成x. 2 l r:求出\([l,r]\)区间中每一个出现的数的最后一次出现位 ...

  9. Codeforces 1093E Intersection of Permutations [CDQ分治]

    洛谷 Codeforces 思路 一开始想到莫队+bitset,发现要T. 再想到分块+bitset,脑子一抽竟然直接开始写了,当然也T了. 最后发现这就是个裸的CDQ分治-- 发现\(a\)不变,可 ...

随机推荐

  1. 盘点一下Redis中常用的Java客户端,或者咱们手写一个?

    Java中那些Redis的客户端 前面我们的所有操作都是基于redis-cli来完成的,那么我们要在Java中操作Redis,怎么做呢?首先我们先来了解一下Redis Serialization Pr ...

  2. ThreadLocal部分源码分析

    结构演进 早起JDK版本中,ThreadLocal内部结构是一个Map,线程为key,线程在"线程本地变量"中绑定的值为Value.每一个ThreadLocal实例拥有一个Map实 ...

  3. Unity——计时器功能实现

    Unity计时器 Demo展示 介绍 游戏中有非常多的计时功能,比如:各种cd,以及需要延时调用的方法: 一般实现有一下几种方式: 1.手动计时 float persistTime = 10f flo ...

  4. 【UE4 C++ 基础知识】<13> 多线程——TaskGraph

    概述 TaskGraph 系统是UE4一套抽象的异步任务处理系统 TaskGraph 可以看作一种"基于任务的并行编程"设计思想下的实现 通过TaskGraph ,可以创建任意多线 ...

  5. vue3.x自定义组件双向数据绑定v-model

    vue2.x 语法 在 2.x 中,在组件上使用 v-model 相当于绑定 value prop 并触发 input 事件: <ChildComponent v-model="pag ...

  6. BUAA_2020_软件工程_软件案例分析作业

    项目 内容 这个作业属于那个课程 班级博客 这个作业的要求在哪里 作业要求 我在这个课程的目标是 学习掌握软件工程的相关知识 这个作业在哪个具体方面帮我实现目标 通过对具体软件案例的分析学习软件工程 ...

  7. BUAA_2020_软件工程_个人项目作业

    作业抬头(1') 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人项目作业 我在这个课程的目标是 了解软件工程的技术,掌握工程化开发的能力 这 ...

  8. Noip模拟54 2021.9.16

    T1 选择 现在发现好多题目都是隐含的状压,不明面给到数据范围里,之凭借一句话 比如这道题就是按照题目里边给的儿子数量不超过$10$做状压,非常邪门 由于数据范围比较小,怎么暴力就怎么来 从叶子节点向 ...

  9. Noip模拟49 2021.9.7

    T1 reverse 又一道板子打假的挂分题,直接挂到倒二.. 考场上思路神奇,居然想到用$bfs$建边然后跑最短路, 其实当时也想到了直接$bfs$,但是不知道为啥觉得$dij$屌就没直接打$bfs ...

  10. 计算机网络传输层之TCP流量控制

    文章转自:https://blog.csdn.net/weixin_43914604/article/details/105531547 学习课程:<2019王道考研计算机网络> 学习目的 ...