Can you answer these queries? HDU - 4027
原题链接
考察:线段树+剪枝
思路:
参考大佬的思路.线段树也能剪枝是我没想到的.
最大的数263最多开方6次就会变成1.考虑到这点可以考虑暴力.每次修改[l,r]实际转化为单点修改,但是要进行剪枝,如果当前区间的最大值已经 = 1,那么就没必要在往下搜.
时间复杂度最坏是O(6*4*N+1e5*log2N)
其中4*N是线段树所有点数,最多遍历6遍所有点.
Code
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
LL a[N];
int n,m;
struct Node{
int l,r;
LL maxn,sum;
}tr[N<<2];
void push_up(int u)
{
tr[u].maxn = max(tr[u<<1].maxn,tr[u<<1|1].maxn);
tr[u].sum = tr[u<<1].sum+tr[u<<1|1].sum;
}
void build(int u,int l,int r)
{
tr[u].l = l,tr[u].r = r;
if(l==r) {tr[u].maxn = tr[u].sum = a[l];return;}
int mid = l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
push_up(u);
}
void modify(int u,int l,int r)
{
if(tr[u].maxn==1) return;
if(tr[u].l>=l&&tr[u].r<=r)
{
if(tr[u].l==tr[u].r)
{
tr[u].sum = sqrt(tr[u].sum*1.0);
tr[u].maxn = tr[u].sum;
return;
}
}
int mid = tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r);
if(mid<r) modify(u<<1|1,l,r);
push_up(u);
}
LL query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum;
int mid = tr[u].l+tr[u].r>>1;
LL res = 0;
if(l<=mid) res+=query(u<<1,l,r);
if(mid<r) res+=query(u<<1|1,l,r);
return res;
}
int main()
{
int kcase = 0;
while(scanf("%d",&n)!=EOF)
{
printf("Case #%d:\n",++kcase);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
scanf("%d",&m);
build(1,1,n);
while(m--)
{
int op,l,r; scanf("%d%d%d",&op,&l,&r);
if(l>r) swap(l,r);
if(op) printf("%lld\n",query(1,l,r));
else modify(1,l,r);
}
printf("\n");
}
return 0;
}