我永远喜欢珂朵莉~

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我永远喜欢珂朵莉~相关的知识,希望对你有一定的参考价值。

我永远喜欢珂朵莉~

题解

首先,除去 x = 1 x=1 x=1的情况,我们的一个数最多进行 l o g   a i log\\,a_{i} logai次除法,所以事实上我们是可以对每个数暴力进行除法的,通过树状数组来维护区间和。
所以对于数进行修改方面我们的时间复杂度是 O ( n log ⁡ 2   n ) O\\left(n\\log^2\\,n\\right) O(nlog2n)
但真正的问题在于我们如何快速地找到我们需要进行修改的数。
由于一个数在 5 × 1 0 5 5\\times 10^5 5×105以内,一个数最多会有 300 300 300个约数左右,我们不妨对于每个数建一棵 T r e a p Treap Treap,表示为这个数倍数的位置有哪些。放心, 1.22 G B 1.22GB 1.22GB的空间再怎么也不会MLE
我们每次操作就直接从 x x x对应的 T r e a p Treap Treap中分裂出区间 [ l , r ] [l,r] [l,r],将里面的数除以 x x x
但当我们除去这个 x x x后可能影响 a i a_{i} ai的其它约数,我们不可能一个一个地进行更改,不如我们改一下原来的定义,改为可能为这个数倍数的数。
因为我们只有除法,所以一个数的约数集合只会不断减少,不会增加,所以我们就不用管加点,只在每次调用这个区间时将不符合条件的点去掉即可。
同理,我们在操作后也会有相当一部分点变得不能并入原树,我们将可以并入的点拿出来建一棵新树后再合并进去就行了。
很明显,这种情况下每个数没进行一次操作,至少减少一个约数的位置,所以这部分时 O ( n d ) O\\left(nd\\right) O(nd)的, d d d表示原数的约数个数。

总时间复杂度 O ( n ( d + log ⁡ 2   n ) + m l o g   n ) O\\left(n(d+\\log^2\\,n)+mlog\\,n\\right) O(n(d+log2n)+mlogn)

源码

#include<bits/stdc++.h> 
using namespace std;
#define MAXM 500005
#define MAXN 100005
#define MAXT 20000005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int inv2=499122177;
const int jzm=2333;
const int zero=10000;
const int lim=500000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,m,root[MAXM],val[MAXN],sta[MAXN],stak,tim;LL tr[MAXN];
vector<int>vec[MAXM];
void insert(int pos,int aw){while(pos<=n)tr[pos]+=1ll*aw,pos+=lowbit(pos);}
LL query(int pos){LL res=0;while(pos)res+=tr[pos],pos-=lowbit(pos);return res;}
struct ming{
	int lson,rson,val,siz,rnd;
	ming(){lson=rson=val=siz=rnd=0;}
};
class FHQ_Treap{
	private:
		ming tr[MAXT];int tot;
		int newnode(int w){
			int rt=++tot;tr[rt].siz=1;tr[rt].val=w;
			tr[rt].rnd=rand();return rt;
		}
		void pushup(int rt){tr[rt].siz=tr[tr[rt].lson].siz+tr[tr[rt].rson].siz+1;}
		void split(int now,int k,int &x,int &y){
			if(!now){x=y=0;return ;}
			if(tr[now].val>k)
				y=now,split(tr[now].lson,k,x,tr[now].lson),pushup(y);
			else x=now,split(tr[now].rson,k,tr[now].rson,y),pushup(x);
		}
		int merge(int x,int y){
			if(!x||!y)return x+y;
			if(tr[x].rnd<tr[y].rnd){
				tr[x].rson=merge(tr[x].rson,y);
				pushup(x);return x;
			}
			tr[y].lson=merge(x,tr[y].lson);
			pushup(y);return y;
		}
		void search(int rt){
			if(tr[rt].lson)search(tr[rt].lson);
			sta[++stak]=tr[rt].val;
			if(tr[rt].rson)search(tr[rt].rson);
		}
	public:
		int build(int l,int r){
			int mid=l+r>>1,rt=newnode(sta[mid]);
			if(l<mid)tr[rt].lson=build(l,mid-1);
			if(r>mid)tr[rt].rson=build(mid+1,r);
			pushup(mid);return rt;
		}
		void modify(int l,int r,int aw){
			if(aw<2||!root[aw])return ;int x1,y1,x2,y2;split(root[aw],r,x1,y1);
			split(x1,l-1,x2,y2);if(!y2){root[aw]=merge(x2,y1);return ;}
			stak=0;search(y2);int tt=0;
			for(int i=1;i<=stak;i++)if(val[sta[i]]%aw==0){
				insert(sta[i],-val[sta[i]]),
				val[sta[i]]/=aw,insert(sta[i],val[sta[i]]);
				if(val[sta[i]]%aw==0)sta[++tt]=sta[i];	
			}
			if(tt)root[aw]=merge(x2,merge(build(1,tt),y1));
			else root[aw]=merge(x2,y1);
		}
}T;
signed main(){
	read(n);read(m);
	for(int i=1;i<=n;i++){
		read(val[i]),insert(i,val[i]);
		for(int j=2;1ll*j*j<=val[i];j++){
			if(val[i]%j)continue;vec[j].pb(i);
			if(val[i]/j!=j)vec[val[i]/j].pb(i);
		}
		vec[val[i]].pb(i);
	}
	for(int i=2;i<=lim;i++){
		stak=0;for(int j=0;j<vec[i].size();j++)sta[++stak]=vec[i][j];
		if(!stak)continue;root[i]=T.build(1,stak);
	}
	for(int i=1;i<=m;i++){
		int opt,l,r,x;read(opt);tim=i;
		if(opt==1)read(l),read(r),read(x),T.modify(l,r,x);
		if(opt==2)read(l),read(r),printf("%lld\\n",query(r)-query(l-1));
	}
	return 0;
}

谢谢!!!

以上是关于我永远喜欢珂朵莉~的主要内容,如果未能解决你的问题,请参考以下文章

珂朵莉树(ODT老司机树)

毒瘤数据结构之珂朵莉树

好Van的珂朵莉树

CF896C Willem, Chtholly and Seniorious 珂朵莉树

hdu4578线段树维护平方和,立方和(加,乘,赋值)或者珂朵莉树

P2787 语文1(chin1)- 理理思维(珂朵莉树)