1. 程式人生 > >Luogu p4145 上帝造題的七分鐘2 題解 線段樹

Luogu p4145 上帝造題的七分鐘2 題解 線段樹

題目連結 這道題其實和上帝造題的七分鐘1沒有什麼關係,是一道線段樹的題。

筆者是第一次看見區間整體開方的題,開始有點慌,結果發現並不難。通過計算,我們不難得出這道題最大可能有的數1e12只需要經過6次開方就可以變成接近1的數,我們又知道如果一個數等於1,那麼它的開方永遠還是1.

因此,我們又可以發現,這道題的資料只有1e5,是可以支援暴力修改的,只需要看這段區間最大值是否超過1. 在這裡插入圖片描述 所以,我們可以發現這道題就是一道線段樹還不加lazy的暴力修改。但是由於筆者是個蒟蒻,讀入優化寫的是int型別硬是沒查出來,結果交了十幾遍五十分 在這裡插入圖片描述 具體程式碼如下

#include<bits/stdc++.h>
using namespace std;
int n,m;
long long p[100010];
struct node{
	int l,r;
	long long value;
}tree[400010];
inline long long read(){
	long long s=0,f=1;char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())s=(s<<3)+(s<<1)+(c^48);
	return s*f;
}
inline void write(long long x){
	if(x<0){putchar('-');x=-x;}
	if(x>9) write(x/10);
	putchar(x%10+'0');
}
void build(int l,int r,int number){
	if(l==r){
		tree[number].value=p[l];
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,number<<1);
	build(mid+1,r,number<<1|1);
	tree[number].value=tree[number<<1].value+tree[number<<1|1].value;
}
void in(int l,int r,int number,int ll,int rr){
	if(r-l+1==tree[number].value)return;
	if(l==r){
		tree[number].value=floor(sqrt(tree[number].value));
		return;
	}
	int mid=(l+r)>>1;
	if(ll<=mid)in(l,mid,number<<1,ll,rr);
	if(rr>mid)in(mid+1,r,number<<1|1,ll,rr);
	tree[number].value=tree[number<<1].value+tree[number<<1|1].value;
}
long long query(int l,int r,int number,int ll,int rr){
	if(ll<=l&&r<=rr){
		return tree[number].value;
	}
	long long s=0;
	int mid=(l+r)>>1;
	if(ll<=mid)s+=query(l,mid,number<<1,ll,rr);
	if(rr>mid)s+=query(mid+1,r,number<<1|1,ll,rr);
	return s;
}
int main(){
	n=read();
	for(int i=1;i<=n;i++)p[i]=read();
	build(1,n,1);
	m=read();
	for(int i=1;i<=m;i++){
		int opt=read(),x=read(),y=read();
		if(x>y)swap(x,y);
		if(opt){
			long long ans=query(1,n,1,x,y);
			write(ans);putchar('\n');
		}
		else in(1,n,1,x,y);
	}
	return 0;
}