题目:http://acm.hdu.edu.cn/showproblem.php?pid=4027
数据很大,很容易发现要用线段树,但是在不能建成普通的叶子树,要弄成区间的,成段的更新。那样每次更改节点的复杂度很大。仿造别人的代码才AC掉,
而且if(trie[id].isOne==1) return;写成了if(trie[id].isOne=1) return; 导致查了半天!!
这题的关键题解是 2^64次方 最多开6次平方根就变成1了,所以只要标记节点内的点是否全部为1....不为1继续改变树。
下面是AC代码:
#include<iostream>
#include<cmath>
#include<map>
using namespace std;
#define N 100005
__int64 a[100005];
struct node
{
int l,m,r;
__int64 num;
int isOne;
}trie[N*3];
void creat(int id,int beg,int end)
{
trie[id].l=beg;
trie[id].r=end;
trie[id].isOne=0;
trie[id].m=(beg+end)>>1;
if(beg==end){
if(a[beg]==1)
trie[id].isOne=1;
trie[id].num=a[beg];
return ;
}
else{
creat(id*2,beg,trie[id].m);
creat(id*2+1,trie[id].m+1,end);
trie[id].num=trie[id*2].num+trie[id*2+1].num;
if(trie[id*2].isOne==1&&trie[id*2+1].isOne==1)
trie[id].isOne=1;
}
}
void update(int id,int beg,int end)
{
if(trie[id].isOne==1) return;
if(trie[id].l==trie[id].r)
{
trie[id].num=(__int64)sqrt(double(trie[id].num));
// cout<<trie[id].num<<endl;
if(trie[id].num==1)
trie[id].isOne=1;
return ;
}
else
{
// cout<<434223423<<endl;
if(trie[id].m>=end)
{
update(id*2,beg,end); //在左子树
}
else if(trie[id].m+1<=beg)
{
update(id*2+1,beg,end); //在右子树
}
else{
update(id*2,beg,trie[id].m);
update(id*2+1,trie[id].m+1,end);
}
}
trie[id].num=trie[id*2].num+trie[id*2+1].num;
if(trie[id*2].isOne==1&&trie[id*2+1].isOne==1)
trie[id].isOne=1;
}
__int64 find(int id,int beg,int end)
{
if(trie[id].isOne==1) return end-beg+1;
if(trie[id].l==beg&&trie[id].r==end){
return trie[id].num;
}
else{
if(trie[id].m>=end){
return find(id*2,beg,end);
}
else if(trie[id].m+1<=beg){
return find(id*2+1,beg,end);
}
else
return find(id*2,beg,trie[id].m)+find(id*2+1,trie[id].m+1,end);
}
}
int main(){
int n,m,i,j,t,x,y,temp,ca=1;
while(scanf("%d",&n)!=EOF){
for(i=1;i<=n;i++){
scanf("%I64dd",&a[i]);
}
creat(1,1,n);
scanf("%d",&m);
printf("Case #%d:\n",ca++);
for(i=0;i<m;i++){
scanf("%d%d%d",&t,&x,&y);
if(x>y){
temp=x;
x=y;
y=temp;
}
if(t==0){
update(1,x,y);
}
else{
printf("%I64d\n",find(1,x,y));
}
}
cout<<endl;
}
return 0;
}