P4145 花神游历各国 [并查集+树状数组 / 线段树]

22 篇文章 0 订阅
17 篇文章 0 订阅

传送门

法1: 发现根号开几次就没了, 于是可以并查集动态维护区间的一段1, 遇到区间一段就直接跳到下一个不为1的地方

如果不是1就树状数组暴力单修

法2: 线段树维护区间最大, 如果最大<=1 就直接跳过, 否则递归修改儿子


树状数组+并查集

#include<bits/stdc++.h>
#define N 100050
#define LL long long
using namespace std;

int fa[N]; int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
LL c[N]; int n,m; LL a[N];
void add(int x,LL val){for(;x<=n;x+=x&-x) c[x] += val;}
LL Quary(int x){LL ans = 0; for(;x;x-=x&-x) ans += c[x]; return ans;}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]); 
		add(i,a[i]); fa[i] = i;
	}
	scanf("%d",&m);
	while(m--){
		int op,l,r; scanf("%d%d%d",&op,&l,&r);
		if(l>r) swap(l,r);
		if(op==1) printf("%lld\n",Quary(r)-Quary(l-1));
		if(op==0){
			for(int i=l;i<=r;){
				LL x = a[i]; x = (LL)sqrt(x);
				add(i,x-a[i]); a[i] = x;
				if(a[i]<=1) fa[i] = i+1;
				int t = find(i); if(t==i) i++; else i = t;
			}
		}
	} return 0;
}

线段树:

#include<bits/stdc++.h>
#define N 100050
#define LL long long
using namespace std;

int n,m; LL a[N];
struct Node{
	int l,r; LL Max,val;
}t[N<<2];

void Pushup(int x){
	t[x].val = t[x<<1].val + t[x<<1|1].val;
	t[x].Max = max(t[x<<1].Max, t[x<<1|1].Max); 
}
void Build(int x,int l,int r){
	t[x].l = l, t[x].r = r;
	if(l==r){t[x].val = t[x].Max = a[l]; return;}
	int mid = (l+r) >> 1;
	Build(x<<1,l,mid); Build(x<<1|1,mid+1,r);
	Pushup(x); 
}
void Sqrt(int x){
	if(t[x].l==t[x].r){
		t[x].val = t[x].Max = (LL)sqrt(t[x].val);
		return;
	}
	if(t[x].Max<=1) return;
	Sqrt(x<<1), Sqrt(x<<1|1);
	Pushup(x);
}
void Update(int x,int L,int R){
	if(L<=t[x].l && t[x].r<=R){
		Sqrt(x); return;
	}
	int mid = (t[x].l+t[x].r) >> 1;
	if(L<=mid) Update(x<<1,L,R);
	if(R>mid) Update(x<<1|1,L,R);
	Pushup(x); 
}
LL Quary(int x,int L,int R){
	if(L<=t[x].l && t[x].r<=R) return t[x].val;
	int mid = (t[x].l+t[x].r) >> 1; LL ans = 0;
	if(L<=mid) ans += Quary(x<<1,L,R);
	if(R>mid) ans += Quary(x<<1|1,L,R);
	return ans;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]); 
	} Build(1,1,n);
	scanf("%d",&m);
	while(m--){
		int op,l,r; scanf("%d%d%d",&op,&l,&r);
		if(l>r) swap(l,r);
		if(op==0) Update(1,l,r);
		if(op==1) printf("%lld\n",Quary(1,l,r));
	} return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值