ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

洛谷 P3987 我永远喜欢珂朵莉~(平衡树)

2020-04-30 20:52:07  阅读:290  来源: 互联网

标签:ch 洛谷 int P3987 k3 k2 朵莉 ind inline


题目链接

题意:给出一个序列 \(a(n)\),需要支持以下两个操作
1 l r x 将 \([l,r]\) 中 \(x\) 的倍数除以 \(x\)
2 l r 求 \([l,r]\) 的和。
\(1 \leq n \leq 10^5\),\(1 \leq a_i \leq 5 \times 10^5\)

真·卡常毒瘤题,加强版还没过
不难发现每个数最多除 \(\log(500000)\) 次,所以总次数不会超过 \(2 \times 10^6\),至于求和,可以用树状数组维护。
所以这道题的难点就变为了怎么找出 \(x\) 的倍数。
我们对于每个 \(x\) 建一棵平衡树,里面插入所有 \(a_i\) 是 \(x\) 的倍数的 \(i\)。
对于一次 \(1\) 操作,只需将第 \(x\) 棵树的 \([l,r]\) 截出来,将数中的 \(x\) 的倍数都除以 \(x\),如果除完之后不是 \(x\) 的倍数,就将它从这个平衡树删除。
就 好 了
代码:(大概要开 O2 才能过)

#include <bits/stdc++.h>
using namespace std;
#define fz(i,a,b)	for(register int i=a;i<=b;i++)
#define fd(i,a,b)	for(register int i=a;i>=b;i--)
//#define int long long
typedef long long ll;
inline int read(){
	int x=0,neg=1;char c=getchar();
	while(!isdigit(c)){
		if(c=='-')	neg=-1;
		c=getchar();
	}
	while(isdigit(c))	x=x*10+c-'0',c=getchar();
	return x*neg;
}
inline void print(ll x){
	(x<=9)?(putchar(x+'0')):(print(x/10),putchar(x%10+'0'));
}
int n=read(),m=read(),a[100005];
int dels[500005],dels_cnt;
ll bit[100005];
inline void add(int x,int y){
	for(int i=x;i<=n;i+=(i&(-i)))	bit[i]+=y;
}
inline ll query(int x){
	ll sum=0;
	for(int i=x;i;i-=(i&(-i)))	sum+=bit[i];
	return sum;
}
struct node{
	int ch[2],ind,key;
};
int qt[100005],qts=0;
node s[20000005];
int rt[500005];
int cnt=0;
vector<int> f[500005];
inline int newnode(int ind){
	s[++cnt].ind=ind;
	s[cnt].key=rand();
	return cnt;
}
inline void build(int &k,int l,int r){
	int mid=(l+r)>>1;
	k=newnode(qt[mid]);
	if(l^mid)	build(s[k].ch[0],l,mid-1);
	if(mid^r)	build(s[k].ch[1],mid+1,r);
}
inline void split(int k,int val,int &a,int &b){
	if(!k){a=b=0;return;}
	(val<s[k].ind)?(b=k,split(s[k].ch[0],val,a,s[k].ch[0])):(a=k,split(s[k].ch[1],val,s[k].ch[1],b));
}
inline int merge(int a,int b){
	if(!a||!b)	return a+b;
	return (s[a].key>s[b].key)?(s[a].ch[1]=merge(s[a].ch[1],b),a):(s[b].ch[0]=merge(a,s[b].ch[0]),b);
}
inline void del(int ind,int x){
	int k1,k2,k3;
	split(rt[x],ind-1,k1,k2);
	split(k2,ind,k2,k3);
	rt[x]=merge(k1,k3);
}
inline void dfs(int k,int x){
	if(!k)	return;
	dfs(s[k].ch[0],x);
	if(a[s[k].ind]%x==0)	add(s[k].ind,-a[s[k].ind]),a[s[k].ind]/=x,add(s[k].ind,a[s[k].ind]);
	if(a[s[k].ind]%x!=0)	dels[++dels_cnt]=s[k].ind;
	dfs(s[k].ch[1],x);
}
inline void solve(int x,int l,int r){
	if(x==1)	return;
	int k1,k2,k3;
	split(rt[x],l-1,k1,k2);
	split(k2,r,k2,k3);
	dels_cnt=0;
	dfs(k2,x);
	rt[x]=merge(merge(k1,k2),k3);
	fz(i,1,dels_cnt)	del(dels[i],x);
}
signed main(){
	srand(time(0));
	fz(i,1,n)	a[i]=read(),add(i,a[i]);
	fz(i,1,n){
		if(!a[i])	continue;
		for(int j=1;j*j<=a[i];j++){
			if(a[i]%j==0){
				f[j].push_back(i);
				if(a[i]/j!=j)	f[a[i]/j].push_back(i);
			}
		}
	}
	fz(i,1,500000){
		if(f[i].size()){
			qts=0;
			for(int j=0;j<f[i].size();j++){
				qt[++qts]=f[i][j];
			}
			build(rt[i],1,qts);
		}
	}
	ll ans=0;
	while(m--){
		int opt=read();
		if(opt&1){
			int l=read(),r=read(),x=read();
			//l^=ans;r^=ans;x^=ans;
			solve(x,l,r);
		}
		else{
			int l=read(),r=read();
			//l^=ans;r^=ans;
			ans=query(r)-query(l-1);
			print(ans);putchar('\n');
		}
	}
}

标签:ch,洛谷,int,P3987,k3,k2,朵莉,ind,inline
来源: https://www.cnblogs.com/ET2006/p/12811099.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有