题目背景

http://sukasuka-anime.com/

虽然2018已经到来很久了,但是就用它作为2018年的第一篇博客,借此表达我对珂学的热爱吧!


题面

https://www.luogu.org/problemnew/show/3987


解题思路

好久好久之前做的一道题了,貌似是洛谷某月赛的题目。。

解题思路什么的早就不记得啦,只能瞎BB了。。

算了,贴个官方标解吧!

可以发现一个数最多被/log次(无视掉1和0的情况)

瓶颈在于如何找出所有该被/的数而不在于如何维护

500000以内的有最多约数的数有200个约数

然后可以用平衡树来维护

把每个i插入ai的所有约数对应的平衡树里面

每次区间[l,r]中x的倍数/x的时候

则在第x个平衡树里面把区间[l,r]截出来然后DFS这个子树

边DFS边删掉里面所有ai/x后不为x倍数的下标i

平衡树访问连续size个数的复杂度为logn+size的

总复杂度O( nd + mlog^2n ) , 空间O( nd ),d为值域内最大约数个数,即200

没错,这是一道很适合新手做的Splay入门题,因为它不仅综合了数学和BIT等其他的知识,而且还具有优秀的数据结构题应有的特点:卡常!!

一开始疯狂T的我,加了几个玄学优化就过了。
具体就是Splay开m棵就够了,Build的时候不要一个个插入,直接线性建树,然后加一堆底层优化就好了!

最后勉勉强强卡过了!

其余一堆细节我都忘了,都是些模拟的操作。


代码

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <vector>
#define maxn 100010
#define maxN 500010
#define maxD 210
#define INF 0x7FFFFFFFusing namespace std;typedef long long LL;int n, m;
int cnt;
int Del[maxn];
bool exist[maxN];
LL a[maxn], BIT[maxn];
vector <int> Num[maxN];struct Data{int type, l, r, x;
}op[maxn];struct Tnode{Tnode *son[2], *fa;int id;inline int Get_d(){return fa->son[1] == this;}inline void Connect(Tnode *now, int d){(son[d] = now)->fa = this;}
}Node[maxn*maxD+maxN*2], *Root[maxN];inline int lowbit(int x){return x & (-x);
}inline void Add(int x, LL v){for(register int i = x; i <= n; i += lowbit(i))  BIT[i] += v;
}inline LL Sum(int x){LL res = 0LL;for(register int i = x; i; i -= lowbit(i))  res += BIT[i];return res;
}inline Tnode *NewTnode(int id){Node[cnt].son[0] = Node[cnt].son[1] = Node[cnt].fa = NULL;Node[cnt].id = id;return Node+cnt++;
}inline void Zig(Tnode *now, Tnode *&tag){Tnode *last = now->fa;int d = now->Get_d();if(now->son[!d])  last->Connect(now->son[!d], d);else  last->son[d] = NULL;if(last == tag){now->fa = tag->fa;tag = now;}else  last->fa->Connect(now, last->Get_d());now->Connect(last, !d);
}inline void Splay(Tnode *now, Tnode *&tag){Tnode *last;while(now != tag){last = now->fa;if(last != tag)  (last->Get_d() ^ now->Get_d()) ? Zig(now, tag) : Zig(last, tag);Zig(now, tag);}
}int FindPre(Tnode *now, int x, int pre){if(!now)  return pre;if(now->id < x)  return FindPre(now->son[1], x, now->id);else  return FindPre(now->son[0], x, pre);
}int FindSuc(Tnode *now, int x, int suc){if(!now)  return suc;if(now->id > x)  return FindSuc(now->son[0], x, now->id);else  return FindSuc(now->son[1], x, suc);
}void Work(Tnode *now, int x, Tnode *&tag){if(now->id == x)  Splay(now, tag);else if(now->id < x)  Work(now->son[1], x, tag);else  Work(now->son[0], x, tag);
}Tnode *Build(int L, int R, int x, Tnode *last){if(L > R)  return NULL;int mid = (L + R) >> 1;Tnode *now = NewTnode(Num[x][mid]);now->fa = last;now->son[0] = Build(L, mid-1, x, now);now->son[1] = Build(mid+1, R, x, now);return now;
}void Delete(int x, int v){int low = FindPre(Root[x], v, -INF);int high = FindSuc(Root[x], v, INF);Work(Root[x], low, Root[x]);Work(Root[x], high, Root[x]->son[1]); Root[x]->son[1]->son[0] = NULL;
}void Dfs(Tnode *now, int x){if(!now)  return;Dfs(now->son[0], x);Dfs(now->son[1], x);LL temp = a[now->id];if(temp % LL(x) != 0){Del[++Del[0]] = now->id;return;}temp /= (LL)x;Add(now->id, temp-a[now->id]);a[now->id] = temp;
}void Update(int l, int r, int x){if(x == 1)  return;int low = FindPre(Root[x], l, -INF);int high = FindSuc(Root[x], r, INF);Work(Root[x], low, Root[x]);Work(Root[x], high, Root[x]->son[1]);Del[0] = 0;Dfs(Root[x]->son[1]->son[0], x);for(register int i = 1; i <= Del[0]; ++i)  Delete(x, Del[i]);
}inline LL Query(int l, int r){return Sum(r) - Sum(l-1);
}int Read(){int x = 0;  char ch = getchar();while(ch < '0' || ch > '9')  ch = getchar();while(ch >= '0' && ch <= '9'){x = (x << 3) + (x << 1) + ch - '0';  ch = getchar();}return x;
}void Print(LL x){if(x > 9)  Print(x / 10);putchar(x % 10 + '0');
}int main(){n = Read();  m = Read();for(register int i = 1; i <= n; ++i){  a[i] = Read();Add(i, a[i]);}for(register int i = 1; i <= m; ++i){op[i].type = Read();  op[i].l = Read();  op[i].r = Read();if(op[i].type == 1){op[i].x = Read();int X = op[i].x;if(X ^ 1 && !exist[X]){  exist[X] = true;  Num[X].push_back(-INF);}}}for(register int i = 1; i <= n; ++i){for(register int j = 1; j * j <= a[i]; ++j){if(a[i] % j)  continue;int d1 = j, d2 = a[i] / j;if(exist[d1])  Num[d1].push_back(i);if(d1 != d2 && exist[d2])  Num[d2].push_back(i);}}for(register int i = 1; i <= m; ++i){if(op[i].type ^ 1)  continue;int X = op[i].x;if(exist[X]){Num[X].push_back(INF);Root[X] = Build(0, Num[X].size()-1, X, NULL);exist[X] = false;}}for(register int i = 1; i <= m; ++i){if(op[i].type == 1)  Update(op[i].l, op[i].r, op[i].x);else{  Print(Query(op[i].l, op[i].r));putchar('\n');}}return 0;
}

洛谷 P3987 我永远喜欢珂朵莉~(Splay+BIT+无限卡常)相关推荐

  1. 洛谷P3987 我永远喜欢珂朵莉~ 树状数组+vector(暴力)

    题目链接:我永远喜欢珂朵莉- 在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去.逐渐消逝的未来.我回来了,纵使日薄西山,即便看不到 ...

  2. 洛谷P3987 我永远喜欢珂朵莉~(set 树状数组)

    题意 题目链接 Sol 不会卡常,自愧不如.下面的代码只有66分.我实在懒得手写平衡树了.. 思路比较直观:拿个set维护每个数出现的位置,再写个线段树维护区间和 #include<bits/s ...

  3. 珂朵莉树(永远喜欢珂朵莉/doge)

    目录 前言 可能用到前置知识 背景 构建珂朵莉树 核心函数 珂朵莉树在实际题目使用 对珂朵莉树的一些感想 最后的最后 前言 最近刚刚学内容大概是借鉴的吧,感觉这个数据结构不仅简单,还很强,有着非常柯学 ...

  4. 洛谷P5072 [YNOI2015]盼君勿忘 莫队+unordered_set+毒瘤卡常

    在太阳西斜的这个世界里,置身天上之森.等这场战争结束之后,不归之人与望眼欲穿的众人, 人人本着正义之名,长存不灭的过去.逐渐消逝的未来.我回来了,纵使日薄西山,即便看不到未来,此时此刻的光辉,盼君勿忘 ...

  5. [转]我的数据结构不可能这么可爱!——珂朵莉树(ODT)详解

    参考资料: Chtholly Tree (珂朵莉树) (应某毒瘤要求,删除链接,需要者自行去Bilibili搜索) 毒瘤数据结构之珂朵莉树 在全是珂学家的珂谷,你却不知道珂朵莉树?来跟诗乃一起学习珂朵 ...

  6. 一种黑科技:珂朵莉树

    首先要明白的是:珂朵莉树(ODT)是一种用来骗分的暴力数据结构. 珂朵莉树的思想是利用集合set,把相同且连续的元素合并为一个个区间,从而进行区间修改:因此,珂朵莉树是区间的集合,这点可以通过定义结构 ...

  7. 浅谈珂朵莉树(ODT)

    前言 珂学家狂喜( 文章目录 前言 一.珂朵莉树来源 二.珂朵莉树 1.珂朵莉树有什么用? 2.原理是什么? a.存储 b.分割结点 c.推平 d.剩余操作 3.复杂度分析 三.珂朵莉树例题 1.P4 ...

  8. 浅谈珂朵莉树(Chtholly Tree)——暴力而玄学的数据结构

    关于它很珂学的名字- 珂朵莉树(Chtholly Tree),又称老司机树(Old Driver Tree),起源于CodeFoeces平台上编号为896C的一道题-- " Willem, ...

  9. 我的算法不可能这么简单—珂朵莉树

    文章目录 进入正题 珂朵莉树的起源 题目简述 题目分析 珂朵莉树的实现 萌新三连 1.明明查询的右端点是12,但是要split(13)呢? 2.为什么要先分裂右端点,然后再分裂左端点呢? 3.获取到区 ...

  10. CF915E Physical Education Lessons(珂朵莉树)

    中文题面 据说正解是动态开点线段树而且标记也不难下传的样子 然而这种区间推平的题目还是喜欢写珂朵莉树啊--码量小-- 虽然真要构造的话随便卡-- 1 //minamoto 2 #include< ...

最新文章

  1. tm matlab,[转载]关于matlab中textread
  2. (C++)归并排序的递归与非递归实现
  3. php读文阻塞,php socket编程 读完成后写阻塞
  4. go语言中goroutine池
  5. mysql排序由低到高_MySQL入门系列(四)—— 排序查询
  6. python 数据平滑_数据平滑方法的原理和应用
  7. aes加密算法python语言实现_python-AES加密解密
  8. java 钩子 64位 操作系统_Java与系统钩子
  9. python调用百度地图画轨迹图_利用python和百度地图API实现数据地图标注的方法
  10. fme csmapreprojector转换器使用高程异常模型进行高程基准转换
  11. 用知识图谱解读抑郁症——树洞
  12. 开源问答系统开源软件
  13. ElasticSearch 学习笔记(一)
  14. 甲骨文官网下载jdk历史版本
  15. 数据结构常见问题系列(二)
  16. 【iOS-UIImagePickerController访问相机和相册】
  17. LVS负载均衡集群——NAT
  18. JSON does not allow non-finite numbers
  19. java 反编译器源码分析
  20. 在RSS服务器上订阅网站,快速服务器上的RSS订阅实现

热门文章

  1. 魔兽世界地图插件制作代码
  2. 《彼得林奇的成功投资》读书笔记
  3. QT应用编程: 基于FFMPEG设计的流媒体播放器(播放rtmp视频流)
  4. 配置Android的SDK,DNK,JDK,ANT打包APK环境
  5. 2020第十二届全国大学生数学竞赛初赛试题及答案(江苏非数)
  6. ASP.NET2.0 ReportingServices,报表灵魂的收割者(一)
  7. 代理服务器和IP加速器之间有什么关系?
  8. cas5.3.2单点登录-配置记住我(十六)
  9. Javaweb实现登录界面“记住我”功能
  10. PAT.1143 Lowest Common Ancestor