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
#include
#include
#include
#include
#include
#include
#define maxn 100010
#define maxN 500010
#define maxD 210
#define INF 0x7FFFFFFF
using 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;
}