P4690 [Ynoi2016] 镜中的昆虫

区间赋值区间数颜色, n ≤ 1 0 5 n \leq 10^5 n≤105,值域 [ 1 , 1 0 9 ] [1,10^9] [1,109],要求线性空间。

sol

首先考虑经典数颜色套路,设 p r e i pre_i prei​ 表示上一个与 a i a_i ai​ 相同的数的位置。

对于区间赋值操作,我们发现性质: ∀ i ∈ ( l , r ] , p r e i ← i − 1 \forall i\in(l,r],pre_i ←i-1 ∀i∈(l,r],prei​←i−1,对于 i = l i=l i=l 或区间外的情况特判即可。

考虑使用 ODT 维护 p r e pre pre 的修改,一个 ODT 维护序列,一个 ODT 数组维护颜色位置,均摊修改次数为 O ( n ) \mathcal O(n) O(n)(增加节点总数 O ( n ) \mathcal O(n) O(n),删除节点总数 O ( n ) \mathcal O(n) O(n)),时间复杂度 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn)。

那么问题转化为带修求 ∑ i = l r [ p r e i < l ] \sum\limits_{i=l}^{r}[pre_i<l] i=l∑r​[prei​<l],考虑到要求线性空间,故使用三维 cdq,时间复杂度 O ( n log ⁡ 2 n ) \mathcal O(n \log^2 n) O(nlog2n)。

时间复杂度 O ( n log ⁡ 2 n ) \mathcal O(n \log ^2 n) O(nlog2n),空间复杂度 O ( n ) \mathcal O(n) O(n)。

详见代码。

#include <bits/stdc++.h>using namespace std;namespace Fread
{const int SIZE = 1 << 21;char buf[SIZE], *S, *T;inline char getchar(){if (S == T){T = (S = buf) + fread(buf, 1, SIZE, stdin);if (S == T)return '\n';}return *S++;}
}namespace Fwrite
{const int SIZE = 1 << 21;char buf[SIZE], *S = buf, *T = buf + SIZE;inline void flush(){fwrite(buf, 1, S - buf, stdout);S = buf;}inline void putchar(char c){*S++ = c;if (S == T)flush();}struct NTR{~NTR(){flush();}} ztr;
}#ifdef ONLINE_JUDGE
#define getchar Fread::getchar
#define putchar Fwrite::putchar
#endifinline int read()
{int x = 0, f = 1;char c = getchar();while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}while(c >= '0' && c <= '9'){x = (x << 3) + (x << 1) + c - 48;c = getchar();}return x * f;
}inline void write(int x)
{if(x < 0) putchar('-'), x = -x;if(x > 9) write(x / 10);putchar(x % 10 + 48);
}const int _ = 2e5 + 10, M = 1e6 + 10;int n, m, tot, a[_], cnt, b[_], ans[_], d[_], pre[_];struct Query
{int opt, l, r, x;
} q[_];struct Node
{int x, y, z, k, d, ans;inline bool operator < (const Node &t) const{return x != t.x ? x < t.x : (y != t.y ? y < t.y : z < t.z);}
} p[M], c[M >> 1];#define pii pair<int, int>
#define pa set<pii>::iteratorstruct Col
{set<pii> cl, v[_];inline void split(int k){pa it = cl.lower_bound({k + 1, 0});int r = it->first - 1;--it;int l = it->first;if(k == r) return;int c = it->second;cl.erase(it);cl.insert({l, c});cl.insert({k + 1, c});v[c].erase({l, r});v[c].insert({l, k});v[c].insert({k + 1, r});}inline void Insert(int l, int r, int c, int t){split(l - 1), split(r);for(pa it = cl.lower_bound({l, 0}); it-> first <= r;){int x = it->first, y = it->second;++it;int z = it->first - 1;cl.erase({x, y});v[y].erase({x, z});if(x == l){int e = (--(v[c].upper_bound({x, 0})))->second;if(pre[x] != e){p[++tot] = {t, x, pre[x], 0, -1, 0};pre[x] = e;p[++tot] = {t, x, pre[x], 0, 1, 0};}}else{if(pre[x] != x - 1){p[++tot] = {t, x, pre[x], 0, -1, 0};pre[x] = x - 1;p[++tot] = {t, x, pre[x], 0, 1, 0};}}x = z + 1;z = (v[y].lower_bound({x, 0}))->first;int e = (--v[y].lower_bound({l, 0}))->second;if(z > r && z <= n && pre[z] != e){p[++tot] = {t, z, pre[z], 0, -1, 0};pre[z] = e;p[++tot] = {t, z, pre[z], 0, 1, 0};}}pa it = v[c].lower_bound({r + 1, 0});int x = it->first;if(x <= n && pre[x] != r){p[++tot] = {t, x, pre[x], 0, -1, 0};pre[x] = r;p[++tot] = {t, x, pre[x], 0, 1, 0};}v[c].insert({l, r});cl.insert({l, c});x = r + 1;if(x <= n){it = cl.lower_bound({x, 0});int y = it->second;int e = (--v[y].lower_bound({x, 0}))->second;if(pre[x] != e){p[++tot] = {t, x, pre[x], 0, -1, 0};pre[x] = e;p[++tot] = {t, x, pre[x], 0, 1, 0};}}}
} col;inline void update(int x, int v)
{++x;while(x < _) d[x] += v, x += x & -x;
}inline int query(int x)
{++x;int res = 0;while(x) res += d[x], x -= x & -x;return res;
}void solve(int l, int r)
{if(l >= r) return;int mid = (l + r) >> 1;solve(l, mid), solve(mid + 1, r);int i = l, j = mid + 1, k = 0;bool flg = (l != 1 || r != tot);while(i <= mid && j <= r)if(p[i].y <= p[j].y){if(p[i].k == 0) update(p[i].z, p[i].d);if(flg) c[k++] = p[i];++i;}else{if(p[j].k == 1) p[j].ans += query(p[j].z);if(flg) c[k++] = p[j];++j;}while(i <= mid){if(p[i].k == 0) update(p[i].z, p[i].d);if(flg) c[k++] = p[i];++i;}while(j <= r){if(p[j].k == 1) p[j].ans += query(p[j].z);if(flg) c[k++] = p[j];++j;}for(int i = l; i <= mid; ++i) if(p[i].k == 0) update(p[i].z, -p[i].d);if(flg) for(int i = 0; i < k; ++i) p[i + l] = c[i];
}signed main()
{n = cnt = read(), m = read();for(int i = 1; i <= n; ++i) a[i] = b[i] = read();for(int i = 1; i <= m; ++i){q[i].opt = read(), q[i].l = read(), q[i].r = read();if(q[i].opt == 1) b[++cnt] = q[i].x = read();}sort(b + 1, b + cnt + 1);cnt = unique(b + 1, b + cnt + 1) - b - 1;for(int i = 1; i <= n; ++i) a[i] = lower_bound(b + 1, b + cnt + 1, a[i]) - b;for(int i = 1; i <= m; ++i) if(q[i].opt == 1) q[i].x = lower_bound(b + 1, b + cnt + 1, q[i].x) - b;for(int i = 1; i <= cnt; ++i) col.v[i].insert({0, 0});for(int i = 1; i <= n; ++i){pre[i] = (--col.v[a[i]].end())->second;p[++tot] = {0, i, pre[i], 0, 1, 0};col.v[a[i]].insert({i, i});col.cl.insert({i, a[i]});}for(int i = 1; i <= cnt; ++i) col.v[i].insert({n + 1, 0});col.cl.insert({0, 0}), col.cl.insert({n + 1, n + 1});for(int i = 1; i <= m; ++i)if(q[i].opt == 1) col.Insert(q[i].l, q[i].r, q[i].x, i);else p[++tot] = {i, q[i].r, q[i].l - 1, 1, 1, 0}, p[++tot] = {i, q[i].l - 1, q[i].l - 1, 1, -1, 0};sort(p + 1, p + tot + 1);solve(1, tot);for(int i = 1; i <= tot; ++i) if(p[i].k) ans[p[i].x] += p[i].ans * p[i].d;for(int i = 1; i <= m; ++i) if(q[i].opt == 2) write(ans[i]), putchar('\n');return 0;
}

P4690 [Ynoi2016] 镜中的昆虫相关推荐

  1. [Ynoi2016] 镜中的昆虫——浅谈区间种类数问题

    诈尸啦~ 这篇博客是很久之前就想写的,总结一些关于区间种类数的问题, 正好一早上都在偏远机房上课,又不想写项目,就随便更新一点: [Ynoi2016] 镜中的昆虫 题意: 给定一个长度为 n n n ...

  2. opencv-python:16_形态学处理【二】(开操作、闭操作、形态学梯度、顶帽变换、黑帽变换,去除皮肤镜中的毛发噪音、cv2.morphologyEx())

    形态学处理[二] 开操作.闭操作.形态学梯度.顶帽变换.黑帽变换 相关函数有:cv2.morphologyEx().cv2.getStructuringElement() 有趣的应用:去除皮肤镜中的毛 ...

  3. 听录——热带雨林中的昆虫

    Title: Bugs 电影:热带雨林中的昆虫 Listener: TnTTools & XiaoTian 听录:TnTTools & XiaoTian Thanks to: wofe ...

  4. 智能健身镜中的晶振应用

    智能健身镜,是一款人工智能+互联网技术深度结合的智能健身产品,它打破了传统健身所固有的模式,让足不出户的我们也能拥有健康的生活,那么智能健身镜使用到哪些晶振? 晶振在智能健身镜的作用 智能健身镜是以硬 ...

  5. P8441 旭日东升(二维数点经典套路)

    P8441 旭日东升 维护一个不可重集合的序列 \(a\),长度为 \(n\).支持以下两种操作: l r x 对于每个 \(l\le i\le r\),将 \(x\) 并入 \(a_i\). l r ...

  6. 2019年二月刷题列表

    Preface 虽然二月剩下没多少了,但是为了勉强保持格式还是写一写吧 这个月的首要目标就是在剩下的时间里让这个月的做题数争取达到\(50\),不过感觉希望渺茫啊 初三中考百天倒计时要来了,所以为此我 ...

  7. ZJOI2019Round#1

    考的这么差二试基本不用去了 不想说什么了.就把这几天听课乱记的东西丢上来吧 这里是二试乱听课笔记ZJOI2019Round#2 ZJOI Round#1 Day1 M.<具体数学>选讲 罗 ...

  8. 幻璃镜服务器维护中,【公告】丨幻璃镜6月1日维护更新说明

    原标题:[公告]丨幻璃镜6月1日维护更新说明 更新公告 [幻璃镜]六一维护更新说明 各位亲爱的小伙伴们有没有很期待六一的更新呢? 小缃特别为大家整理了更新内容预告 驭灵[芙谣]登场~因爱生恨的赤鱬族痴 ...

  9. 名著中的经典语录(转自网络)

    1.神要是公然去跟人作对,那是任何人都难以对付的. (<荷马史诗>) 2.生存还是毁灭,这是一个值得思考的问题. (<哈姆霄特>) 3.善良人在追求中纵然迷惘,却终将意识到有一 ...

最新文章

  1. 剑桥大学:机器学习模型部署都有哪些坑?
  2. 样例解释:1013 数素数 (20分)
  3. nodejs启动机制分析
  4. python concat_python中merge、concat用法
  5. 大数据学习(09)--spark学习
  6. 【跃迁之路】【671天】程序员高效学习方法论探索系列(实验阶段428-2018.12.15-16)...
  7. pascal闪电入门系列目录
  8. char强制类型转换为int_彻底理解Java中的基本数据类型转换(自动、强制、提升)...
  9. windows系统bat批处理 windows 关机,重启,锁定,休眠,注销
  10. python IO多路复用之select
  11. 极光IM简单代码(代码比较清晰)
  12. 2022-2027年(新版)中国钢铁产业运行状况及需求前景预测报告
  13. SpringMVC i18n国际化资源文件路径配置
  14. 支付宝第三代理支付 - 支付宝客户端授权
  15. Windows电脑上搭建Radius 服务器并实现802.1X认证
  16. python玩汉诺塔游戏攻略
  17. Oracle gc等待事件的发现、处理与预防
  18. java爬取论坛信息_Java爬取校内论坛新帖
  19. 商场三十六计——第8计 “暗渡陈仓”
  20. 郁闷的时候看下,心情也许会好一些(转自CSDN)

热门文章

  1. 【华为云主机迁移服务SMS,使用指南 (linux版本)】
  2. Xubuntu 搜狗输入法安装
  3. input js number 整数_数字千分位处理,number.js,js保留两位,整数强制保留两位小数...
  4. 平衡车Car_Balance(一)——电机
  5. python模块—inspect
  6. c语言求三科平均成绩,C语言 4个人,姓名、学号三科成绩,求出平均成绩,按平均成绩由高到低 代码好多错误,不知道那错了,求解...
  7. JAVA多维分析报表怎么做_程序数据集上的多维分析
  8. 《炬丰科技-半导体工艺》晶圆背面研磨与湿式刻蚀工艺
  9. 免费域名 免费空间 免费主页空间 免费动态主页空间
  10. Android中自定义TextView的形状--圆形-椭圆形-圆角矩形-线条