题目大意:n个数字,m次操作,支持修改一个数字和查询一个区间内每种数字最大出现位置减最小出现位置的和。(n,m<=100,000)

做法:把每个数字表示成二维平面上的点,第一维是在数组中的位置,第二维是在数组中前一个相同数字的位置,权值为这两个位置的差,询问等同于求矩形和,修改时会影响自己和相邻的相同数字,每种开一个set维护即可。矩形和可以用cdq分治,不容易被卡空间。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<queue>
#include<map>
#include<set>
using namespace std;
inline int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
#define MN 100000
#define N 131072
set<int> s[MN+];
int a[MN+],ls[MN+],wn,qn,pn;
long long ans[MN+],t[N*+];
struct work{int t,a,b,c;}w[MN*+];
struct P{int t,a,b,c,d;}p[MN*+];
bool cmp(const P&a,const P&b){return a.a==b.a?a.t<b.t:a.a<b.a;}
void add(int k,int x){for(k+=N;k;k>>=)t[k]+=x;}
long long query(int l,int r)
{
long long res=;
for(l+=N-,r+=N+;l^r^;l>>=,r>>=)
{
if(~l&)res+=t[l+];
if( r&)res+=t[r-];
}
return res;
}
void solve(int l,int r)
{
int mid=l+r>>,i;
if(l<r)solve(l,mid),solve(mid+,r);
for(pn=,i=l;i<=mid;++i)if(w[i].t<)p[++pn]=(P){,w[i].a,w[i].b,w[i].c,};
for(;i<=r;++i)if(w[i].t>)p[++pn]=(P){,w[i].a-,w[i].a,w[i].b,w[i].c},
p[++pn]=(P){,w[i].b,w[i].a,w[i].b,w[i].c};
sort(p+,p+pn+,cmp);
for(i=;i<=pn;++i)
{
if(p[i].t==)add(p[i].b,p[i].c);
if(p[i].t==)ans[p[i].d]-=query(p[i].b,p[i].c);
if(p[i].t==)ans[p[i].d]+=query(p[i].b,p[i].c);
}
for(i=;i<=pn;++i)if(p[i].t==)add(p[i].b,-p[i].c);
}
int main()
{
int n,m,i,t,x,y;
n=read();m=read();
for(i=;i<=n;s[a[i]].insert(ls[a[i]]=i),++i)
if(ls[a[i]=read()])w[++wn]=(work){,i,ls[a[i]],i-ls[a[i]]};
for(i=;i<=m;++i)
{
t=read();x=read();y=read();
if(t==)
{
set<int>::iterator i=s[a[x]].find(x),j=i,k=i;++k;
if(i!=s[a[x]].begin())
{
--j;w[++wn]=(work){,x,*j,*j-x};
if(k!=s[a[x]].end())w[++wn]=(work){,*k,*j,*k-*j};
}
if(k!=s[a[x]].end())w[++wn]=(work){,*k,x,x-*k};
s[a[x]].erase(i);
s[a[x]=y].insert(x);
i=j=k=s[y].find(x);++k;
if(i!=s[y].begin())
{
--j;w[++wn]=(work){,x,*j,x-*j};
if(k!=s[y].end())w[++wn]=(work){,*k,*j,*j-*k};
}
if(k!=s[y].end())w[++wn]=(work){,*k,x,*k-x};
}
else w[++wn]=(work){,x,y,++qn};
}
solve(,wn);
for(i=;i<=qn;++i)printf("%I64d\n",ans[i]);
}

[Codeforces]848C - Goodbye Souvenir的更多相关文章

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

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

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

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

  3. [Codeforces]849E Goodbye Souvenir

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

  4. Codeforces 848C (cdq分治)

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

  5. 【Codeforces 848C】Goodbye Souvenir

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

  6. CF848C:Goodbye Souvenir(CDQ分治)

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

  7. codeforces 848c - two TVs

    2017-08-22 15:42:44 writer:pprp 参考:http://blog.csdn.net/qq_37497322/article/details/77463376#comment ...

  8. 【Codeforces Round 431 (Div. 2) A B C D E五个题】

    先给出比赛地址啦,感觉这场比赛思维考察非常灵活而美妙. A. Odds and Ends ·述大意:      输入n(n<=100)表示长度为n的序列,接下来输入这个序列.询问是否可以将序列划 ...

  9. Codeforces Goodbye 2018

    Goodbye 2018 可能是我太菜考试的时候出不了$E$ 可能是我太菜考试的时候调不出$F$ 所以转化为手速场之后手速还上不去.jpg A 模拟题意... #include <cstdio& ...

随机推荐

  1. C语言指针作业总结

    学号 姓名 作业地址 PTA实验作业5 PTA排名2 阅读代码2 总结1 代码规范 总分 是否推荐博客 推荐理由 32 **薇 http://www.cnblogs.com/linyiwei/p/80 ...

  2. 学号:201621123032 《Java程序设计》第11周学习总结

    1:本周学习总结 1.1.:以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 2:书面作业 2.1.: 源代码阅读:多线程程序BounceThread 1.1: BallRunnable类有什 ...

  3. DML数据操作语言之谓词,case表达式

    谓词:就是返回值是真值的函数. 前面接触到的“>” “<” “=”等称为比较运算符,它们的正式名称就是比较谓词.因为它们比较之后返回的结果是真值. 由于谓词 返回的结果是一个真值 ,即tr ...

  4. 2017 清北济南考前刷题Day 3 morning

    实际得分:100+0+0=100 T1 右上角是必败态,然后推下去 发现同行全是必胜态或全是必败态,不同行必胜必败交叉 列同行 所以n,m 只要有一个是偶数,先手必胜 #include<cstd ...

  5. 2017 清北济南考前刷题Day 3 afternoon

    期望得分:100+40+100=240 实际得分:100+40+100=240 将每个联通块的贡献乘起来就是答案 如果一个联通块的边数>点数 ,那么无解 如果边数=点数,那么贡献是 2 如果边数 ...

  6. hdu 3642 Get The Treasury

    Get The Treasury http://acm.hdu.edu.cn/showproblem.php?pid=3642 Time Limit: 10000/5000 MS (Java/Othe ...

  7. day-5 python协程与I/O编程深入浅出

    基于python编程语言环境,重新学习了一遍操作系统IO编程基本知识,同时也学习了什么是协程,通过实际编程,了解进程+协程的优势. 一.python协程编程实现 1.  什么是协程(以下内容来自维基百 ...

  8. JAVA_SE基础——31.this关键字

    黑马程序员入学blog... 也算是学习笔记体会. this的通俗解释: 有一个A类,一个B方法,一个C变量,其中B和C都在类A中 this.B()就是调用A类中的B方法 this.C=1(假设C是一 ...

  9. MSSQL---extents

    一.MSSQLextent分两种: 1. Mixed extent:每个表或索引创建时,MSSQL并不给它分配一个extent,而是在mixed extnet内分配一个页,空间需求扩大时,再分配一个… ...

  10. Connect Appium Server Fail.A new session could not be created

    1.由于安卓测试机性能低下,并不能支持测试工作,想安装一个模拟器帮助测试,然后发现群里有朋友发了一个夜神模拟器..下载..安装..美滋滋的准备运行脚本.What..居然报错了..orz..然后百度查找 ...