Codeforces 848C (cdq分治)
Codeforces 848C Goodbye Souvenir
Problem :
给一个长度为n的序列,有q个询问。一种询问是修改某个位置的数,另一种询问是询问一段区间,对于每一种值出现的最右端点的下标与最左端点的下标的差值求和。
Solution :
定义pre[i] 为 第i个位置的数字上一次出现位置,对于询问l, r 就是对于所有满足
l <= pre[i] < i <= r 的点求和,权值为 i - pre[i]。
因此可以把这个看作是三维偏序的问题,第一维时间,第二维,第三维pre[i], i,用cdq分治求解。
对每一种值开一个set进行预处理,把每一次修改造成的影响表示成 pre[i], i, val 的形式。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 8;
int n, q, tot, num;
int a[N];
long long ans[N];
struct node
{
int type, x, y, id;
bool operator < (const node &b) const
{
return x < b.x || x == b.x && type < b.type;
}
void print()
{
cout << type << " " << x << " " << y << " " << id << endl;
}
}Q[N], tmp[N];
set <int> S[N];
struct BIT
{
long long a[N];
int len;
void init(int l)
{
len = l;
for (int i = 0; i < len; ++i) a[i] = 0;
}
void insert(int x, int y)
{
for (int i = x; i < len; i += i & (-i))
a[i] += y;
}
long long query(int x)
{
long long res = 0;
for (int i = x; i > 0; i -= i & (-i))
res += a[i];
return res;
}
void clear(int x)
{
for (int i = x; i < len; i += i & (-i))
if (a[i] != 0) a[i] = 0; else break;
}
}T;
void cdq(int l, int r)
{
if (l == r) return;
int mid = l + r >> 1;
cdq(l, mid);
cdq(mid + 1, r);
int i = l, j = mid + 1;
for (int k = l; k <= r; ++k)
if (j > r || i <= mid && Q[i] < Q[j])
{
tmp[k] = Q[i++];
if (tmp[k].type == 1)
{
T.insert(n - tmp[k].y + 1, tmp[k].id);
}
}
else
{
tmp[k] = Q[j++];
if (tmp[k].type == 2)
{
ans[tmp[k].id] += T.query(n - tmp[k].y + 1);
}
}
for (int k = l; k <= r; ++k)
{
Q[k] = tmp[k];
T.clear(n - tmp[k].y + 1);
}
}
void update(int pos, int y)
{
if (a[pos] == y) return;
auto it = S[a[pos]].find(pos);
auto it1 = it; it1--;
auto it2 = it; it2++;
Q[++tot] = (node){1, *it, *it1, *it1 - *it};
Q[++tot] = (node){1, *it2, *it, *it - *it2};
Q[++tot] = (node){1, *it2, *it1, *it2 - *it1};
S[a[pos]].erase(pos);
a[pos] = y; S[a[pos]].insert(pos);
it = S[a[pos]].find(pos);
it1 = it; it1--;
it2 = it; it2++;
Q[++tot] = (node){1, *it, *it1, *it - *it1};
Q[++tot] = (node){1, *it2, *it, *it2 - *it};
Q[++tot] = (node){1, *it2, *it1, *it1 - *it2};
}
void init()
{
cin >> n >> q;
tot = 0;
for (int i = 1; i <= n; ++i) S[i].insert(0), S[i].insert(n + 1);
for (int i = 1; i <= n; ++i)
{
int x; cin >> x; a[i] = x;
S[x].insert(i);
auto it = S[x].find(i);
it--;
Q[++tot] = (node){1, i, *it, i - (*it)};
}
num = 0;
for (int i = 1; i <= q; ++i)
{
int type, x, y;
cin >> type >> x >> y;
if (type == 2)
{
Q[++tot] = (node){2, y, x, ++num};
}
else
{
update(x, y);
}
}
}
void solve()
{
T.init(n + 10);
cdq(1, tot);
for (int i = 1; i <= num; ++i)
cout << ans[i] << endl;
}
int main()
{
cin.sync_with_stdio(0);
init();
solve();
}
Codeforces 848C (cdq分治)的更多相关文章
- 【题解】Radio stations Codeforces 762E CDQ分治
虽然说好像这题有其他做法,但是在问题转化之后,使用CDQ分治是显而易见的 并且如果CDQ打的熟练的话,码量也不算大,打的也很快,思维难度也很小 没学过CDQ分治的话,可以去看看我的另一篇博客,是CDQ ...
- Radio stations CodeForces - 762E (cdq分治)
大意: 给定$n$个三元组$(x,r,f)$, 求所有对$(i,j)$, 满足$i<j, |f_i-f_j|\le k, min(r_i,r_j)\ge |x_i-x_j|$ 按$r$降序排, ...
- Codeforces 669E cdq分治
题意:你需要维护一个multiset,支持以下操作: 1:在某个时间点向multiset插入一个数. 2:在某个时间点在multiset中删除一个数. 3:在某个时间点查询multiset的某个数的个 ...
- Tufurama CodeForces - 961E (cdq分治)
题面 One day Polycarp decided to rewatch his absolute favourite episode of well-known TV series " ...
- AI robots CodeForces - 1045G (cdq分治)
大意: n个机器人, 位置$x_i$, 可以看到$[x_i-r_i,x_i+r_i]$, 智商$q_i$, 求智商差不超过$k$且能互相看到的机器人对数. 这个题挺好的, 关键是要求互相看到这个条件, ...
- Codeforces 848C Goodbye Souvenir(CDQ 分治)
题面传送门 考虑记录每个点的前驱 \(pre_x\),显然答案为 \(\sum\limits_{i=l}^{r} i-pre_i (pre_i \geq l)\) 我们建立一个平面直角坐标系,\(x\ ...
- Codeforces 848C Goodbye Souvenir [CDQ分治,二维数点]
洛谷 Codeforces 这题我写了四种做法-- 思路 不管做法怎样,思路都是一样的. 好吧,其实不一样,有细微的差别. 第一种 考虑位置\(x\)对区间\([l,r]\)有\(\pm x\)的贡献 ...
- Codeforces 1093E Intersection of Permutations [CDQ分治]
洛谷 Codeforces 思路 一开始想到莫队+bitset,发现要T. 再想到分块+bitset,脑子一抽竟然直接开始写了,当然也T了. 最后发现这就是个裸的CDQ分治-- 发现\(a\)不变,可 ...
- Codeforces 1045G AI robots [CDQ分治]
洛谷 Codeforces 简单的CDQ分治题. 由于对话要求互相看见,无法简单地用树套树切掉,考虑CDQ分治. 按视野从大到小排序,这样只要右边能看见左边就可以保证互相看见. 发现\(K\)固定,那 ...
随机推荐
- 5.iOS测试总结
1. 什么是Mock 当我们在做单元测试的过程中,为了保持测试又短又快和测试的隔离性,希望尽可能少地去实例化一些具体的组件.在现在面向对象的系统中,被测试的对象很可能会依赖于几个其他的对象,这时候我们 ...
- windows下常用的一些shell命令
看的视频上都是linux系统的shell命令,和windows区别很多.所以整理了windows常用的一些shell命令. 注意:并不是每个都试验过,使用时还需自己验证下. 学system和os,su ...
- iOS 应用程序内部国际化,不跟随系统语言
前言:网络上关于iOS国际化的文章很多,但基本上都是基于跟随系统语言的国际化,笔者就不赘述了-0 – 今天要讲的是不跟随系统的切换语言版本方案,即程序内部的切换语言版本方案. 一.总则: 应用内部语言 ...
- (转)新手学习System Verilog & UVM指南
从刚接触System Verilog以及后来的VMM,OVM,UVM已经有很多年了,随着电子工业的逐步发展,国内对验证人才的需求也会急剧增加,这从各大招聘网站贴出的职位上也可以看出来,不少朋友可能想尽 ...
- Junit测试集锦
Junit测试集锦 前言: 一个程序从设计很好的状态开始,随着新的功能不断地加入,程序逐渐地失去了原有的结构,最终变成了一团乱麻.所以在开发过程中,对于程序员来说,测试是非常重要的.言归正传,开始Ju ...
- react基础语法(二)常用语法如:样式 ,自定义属性,常用表达式
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- function语句注意事项
function语句 在Javascript中定义一个函数,有两种写法: function foo() { } 和 var foo = function () { } 两种写法完全等价.但是在解析的时 ...
- vue获取v-model数据类型boolean改变成string
问题描述 今天产品问我一线上bug,怎么radio类型改不了 问题分析 看代码,之前的哥们儿是怎么写的 //页面 <div class="ui-form-box"> & ...
- java+selenium+maven+IntelliJ IDEA 搭建简单的UI自动化测试环境
1. 用IntelliJ IDEA新建一个maven工程 2. 在pom.xml中添加依赖: <dependency> <groupId>org.seleniumhq.sele ...
- SV学习之interface
普通的模块使用法:注意我们这里只实现了部分功能....不是完全的读写模块.... module mem_core( input logic wen, input logic ren, ...