您的位置:首页 > 产品设计 > UI/UE

hdu 3893 Wow! Such Sequence!

2014-07-30 23:23 274 查看
多校第三场,除了最水的一个模拟题,唯一会做的题目。但是比赛时一直超时超到死。问了a掉的同学才知道应该怎么写。

这道题目,是线段树,线段树的区间更新。

超时的思路:延时标记为某段区间是否需要算斐波那契。在x==3 时,打标记,不暂时求斐波那契,在查询或者更新单点的时候,如果之前要求做斐波那契,就解斐波那契。结果,不断的超时,超时。

在问了通过的同学的想法时,才知道,他们的延时标记为 在某段区间,是否需要求解斐波那契。但是,在 x == 3 也就是算斐波那契的那个操作时,进行 打标记以及解标记。换句话说,在 单点更新以及查询的时候,与这个延时标记无关。

以下是ac的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 400000
#define LL __int64
LL sum[maxn],col[maxn],f[111];
void init()//求解斐波那契数列
{
f[0] = 1;
f[1] = 1;
for(int i = 2; i <= 92; i++)
{
f[i] = f[i-1] + f[i-2];
}
}
LL change(LL num)//求解那个最接近的斐波那契数,因为个数比较小,所以直接暴力找了
{
if(num<=1)return 1;
LL minn = num;
int temi = 92;
for(int i = 2; i <= 92; i++)
{
LL tem = num - f[i];
if(tem < 0) tem = - tem ;
if(tem<minn)
{
minn = tem;
temi = i ;
}
else break;
}
return f[temi];
}
void pushupSum(int rt)//线段树节点向上更新
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void pushupCol(int rt)//延时标记向上更新
{
col[rt] = col[rt<<1] + col[rt<<1|1];
}
void update(int l,int r,int rt,int L,int R)//在算x==3时用到,进行区间的求解斐波那契的更新
{
//如果该区间里每个数都是斐波那契,那么就不需要再求解斐波那契了,因为一个离斐波那契最近的数就是他自己
if(col[rt] == r-l+1)return ;
if(l==r)//如果该点不是斐波那契,那么进行标记并且求解
{
sum[rt] = change(sum[rt]);
col[rt] = 1;
return ;
}
int m = (l+r)>>1;
if(m>=L)update(lson,L,R);
if(m<R)update(rson,L,R);
pushupCol(rt);
pushupSum(rt);
}
LL query(int l,int r,int rt,int L,int R)//查询L R 区间里的和
{
if(l>=L && r<=R )
{
return sum[rt];
}
int m = (l+r)>>1;
LL an = 0;
if(m>=L) an += query(lson,L,R);
if(m<R) an += query(rson,L,R);
return an;
pushupSum(rt);
}
void updateOne(int l,int r,int rt,int p,int num)//单点更新,在p位置加上num
{
if(l==r)
{
col[rt] = 0;//因为该数字有改动,所以把他的延时标记改为,该数不是斐波那契
sum[rt] += num ;
return ;
}
int m = (l+r)>>1;
if(m>=p)updateOne(lson,p,num);
else if(m<p)updateOne(rson,p,num);
pushupCol(rt);
pushupSum(rt);
}
int main()
{
int n,m,i,j,k,x,y,z;
init();
while(scanf("%d%d",&n,&m)!=-1)
{
memset(sum,0,sizeof(sum));
memset(col,0,sizeof(col));
while(m--)
{
scanf("%d%d%d",&x,&y,&z);
if(x == 1)
{
updateOne(1,n,1,y,z);
}
else if(x == 2)
{
LL ans = query(1,n,1,y,z);
printf("%I64d\n",ans);
}
else if(x == 3)
{
update(1,n,1,y,z);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  hdu 多校联赛 线段树