P4145/#6281/GSS4三题题解(线段树区间开根)
前言:
zhx的PPT上的题
三道题思路,做法完全相同,区别在于输入输出格式
同一份代码A掉3个题真捏麻的爽
题目大意:
区间所有数开根号
区间求和
分析:
开根区间内的一个数 \(a_i\) 在不断开根号下取整的过程中是越来越小的。
经过若干次开根最后会变为\(1\) 。其变成 \(1\) 之后就没有必要对它再进行开根操作了。
在线段树每一个节点维护 \(sum ,maxn\) 表示区间最大值和区间和。如果发现这段区间的最大值等于 \(1\) ,那么再次对它开根结果还是 \(1\) ,区间内的每一个数都没有发生变化。
所以如果修改时遇到一个区间为 \(1\) 的区间就可以直接跳过。
如果不为 \(1\) 就暴力开根它的左右儿子。
为什么暴力不会TLE?因为总共 \(n\) 个数,每个数最多开不超过 \(10\) 次。暴力次数为 \(10n\) 。每次暴力无非是从线段树根走到叶。所以最多只会暴力 \(nlog_n\) 次。
代码:
P4145上帝造题的七分钟 2 / 花神游历各国:
#include<bits/stdc++.h>
#define int long long
#define MAXN 1000086
using namespace std;
int n,m ;
int a[MAXN];
struct T{
int l,r,val,maxn;
}t[MAXN];
void update(int node){
t[node].val=t[node<<1].val+t[node<<1|1].val;
t[node].maxn=max(t[node<<1].maxn,t[node<<1|1].maxn);
}
void build(int l,int r,int node){
t[node].l=l;
t[node].r=r;
if(l==r){
t[node].val=a[l];
t[node].maxn=a[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,node<<1);
build(mid+1,r,node<<1|1);
update(node);
}
void change(int l,int r,int node){
if(t[node].l==t[node].r){
t[node].val=sqrt(t[node].val);
t[node].maxn=sqrt(t[node].maxn);
return ;
}
int mid=(t[node].l+t[node].r)>>1;
if(l<=mid&&t[node<<1].maxn>1)
change(l,r,node<<1);
if(r>mid&&t[node<<1|1].maxn>1)
change(l,r,node<<1|1);
update(node);
}
int ask(int l,int r,int node){
if(l<=t[node].l&&t[node].r<=r){
return t[node].val;
}
int mid=(t[node].l+t[node].r)>>1;
int ans=0;
if(l<=mid) ans+=ask(l,r,node<<1);
if(r>mid) ans+=ask(l,r,node<<1|1);
return ans;
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
cin>>m;
build(1,n,1);
int op,l,r;
for(int i=1;i<=m;i++){
cin>>op>>l>>r;
if(l>r)swap(l,r);
if(op==0){
change(l,r,1);
}
else{
cout<<ask(l,r,1)<<'\n';
}
}
return 0;
}
loj#6281 数列分块入门 5:
#include<bits/stdc++.h>
#define int long long
#define MAXN 1000086
using namespace std;
int n,m ;
int a[MAXN];
inline int read(){
register int x=0;
register bool f=0;
register char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<3)+(x<<1)+c-48;
c=getchar();
}
return f?-x:x;
}
struct T{
int l,r,val,maxn;
}t[MAXN];
void update(int node){
t[node].val=t[node<<1].val+t[node<<1|1].val;
t[node].maxn=max(t[node<<1].maxn,t[node<<1|1].maxn);
}
void build(int l,int r,int node){
t[node].l=l;
t[node].r=r;
if(l==r){
t[node].val=a[l];
t[node].maxn=a[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,node<<1);
build(mid+1,r,node<<1|1);
update(node);
}
void change(int l,int r,int node){
if(t[node].l==t[node].r){
t[node].val=sqrt(t[node].val);
t[node].maxn=sqrt(t[node].maxn);
return ;
}
int mid=(t[node].l+t[node].r)>>1;
if(l<=mid&&t[node<<1].maxn>1)
change(l,r,node<<1);
if(r>mid&&t[node<<1|1].maxn>1)
change(l,r,node<<1|1);
update(node);
}
int ask(int l,int r,int node){
if(l<=t[node].l&&t[node].r<=r){
return t[node].val;
}
int mid=(t[node].l+t[node].r)>>1;
int ans=0;
if(l<=mid) ans+=ask(l,r,node<<1);
if(r>mid) ans+=ask(l,r,node<<1|1);
return ans;
}
signed main(){
int cnt=0;
cin>>n;
// printf("Case #%d:\n",++cnt);
memset(a,0,sizeof(a));
memset(t,0,sizeof(t));
for(int i=1;i<=n;i++){
a[i]=read();
}
//cin>>m;
build(1,n,1);
int op,l,r,c;
for(int i=1;i<=n;i++){
op=read();
l=read();
r=read();
c=read();
if(l>r)swap(l,r);
if(op==0){
change(l,r,1);
}
else{
cout<<ask(l,r,1)<<'\n';
}
}
cout<<endl;
return 0;
}
SPOJ GSS4 Can you answer these queries IV
#include<bits/stdc++.h>
#define int long long
#define MAXN 1000086
using namespace std;
int n,m ;
int a[MAXN];
inline int read(){
register int x=0;
register bool f=0;
register char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<3)+(x<<1)+c-48;
c=getchar();
}
return f?-x:x;
}
struct T{
int l,r,val,maxn;
}t[MAXN];
void update(int node){
t[node].val=t[node<<1].val+t[node<<1|1].val;
t[node].maxn=max(t[node<<1].maxn,t[node<<1|1].maxn);
}
void build(int l,int r,int node){
t[node].l=l;
t[node].r=r;
if(l==r){
t[node].val=a[l];
t[node].maxn=a[l];
return ;
}
int mid=(l+r)>>1;
build(l,mid,node<<1);
build(mid+1,r,node<<1|1);
update(node);
}
void change(int l,int r,int node){
if(t[node].l==t[node].r){
t[node].val=sqrt(t[node].val);
t[node].maxn=sqrt(t[node].maxn);
return ;
}
int mid=(t[node].l+t[node].r)>>1;
if(l<=mid&&t[node<<1].maxn>1)
change(l,r,node<<1);
if(r>mid&&t[node<<1|1].maxn>1)
change(l,r,node<<1|1);
update(node);
}
int ask(int l,int r,int node){
if(l<=t[node].l&&t[node].r<=r){
return t[node].val;
}
int mid=(t[node].l+t[node].r)>>1;
int ans=0;
if(l<=mid) ans+=ask(l,r,node<<1);
if(r>mid) ans+=ask(l,r,node<<1|1);
return ans;
}
signed main(){
int cnt=0;
while(cin>>n){
printf("Case #%d:\n",++cnt);
memset(a,0,sizeof(a));
memset(t,0,sizeof(t));
for(int i=1;i<=n;i++){
a[i]=read();
}
cin>>m;
build(1,n,1);
int op,l,r;
for(int i=1;i<=m;i++){
op=read();
l=read();
r=read();
if(l>r)swap(l,r);
if(op==0){
change(l,r,1);
}
else{
cout<<ask(l,r,1)<<'\n';
}
}
cout<<endl;
}
return 0;
}