hdoj 4893 2014年多校联合3 1007

这道题可以说是标准的线段树的用法,单点更新+区间查询和修改。

不过这里有一个提前要做的工作,那就是每次单点更新的时候也要更新区间。否则的话,区间更新的时候,就得更新到叶子节点,复杂度就成了O(n)了。

那么怎么才能不更新到叶子节点呢,就是加一个标记,表示离它最近的斐波那契数列数。这样每次更新的时候,直接把斐波那契数赋值给sum就可以了。

单点更新的时候,才把标记一层一层的传递下去。

具体看代码吧。不过不知道为什么,C++ 一直WA,G++过了。表示很诧异。

#include
#include
#include
#include
#define maxn 111111
using namespace std;
struct Node
{
	int l,r,c;  //c是标记,表示这个区间或点要变成最近的斐波那契数
	__int64 sum,fsum;  //sum是区间和,fsum是区间的斐波那契数的和
};
Node node[maxn*4];
__int64 f[100];
void init()
{
    int i;
    f[0]=f[1]=1;
    for(i=2;i<93;i++)
        f[i]=f[i-1]+f[i-2];
}
void pushup(int k)   //向上更新
{
    node[k].sum=node[k*2].sum+node[k*2+1].sum;
	node[k].fsum=node[k*2].fsum+node[k*2+1].fsum;
}
void pushdown(int k)   //向下传递
{
    if(node[k].l==node[k].r) return ;
    if(node[k].c)
    {
        node[k*2].c=node[k*2+1].c=1;
        node[k*2].sum=node[k*2].fsum;
        node[k*2+1].sum=node[k*2+1].fsum;
        node[k].c=0;
    }
}
void build_tree(int l,int r,int k)           //建树
{
	node[k].l=l;node[k].r=r;
	node[k].sum=0;
	node[k].c=0;
	node[k].fsum=1;
	if(l==r)
		return ;
	int m=(l+r)/2;
	build_tree(l,m,k*2);
	build_tree(m+1,r,k*2+1);
	pushup(k);
}
void Insert(int k,int num,int d)  //单点更新,顺便更新最近的斐波那契数。这样才能为操作3省时。
{
     pushdown(k);
    if(node[k].l==node[k].r)
    {
         node[k].sum+=d;
         int i=lower_bound(f,f+93,node[k].sum)-f;
         if(i && abs(f[i]-node[k].sum)>=abs(f[i-1]-node[k].sum))
            i=i-1;
         node[k].fsum=f[i];
         return ;
    }
    int m=(node[k].l+node[k].r)/2;
    if(num<=m)
        Insert(k*2,num,d);
    else Insert(k*2+1,num,d);
    pushup(k);
}
void change(int k,int l,int r)  //区间更新,打完标记就返回,不要更新到叶子节点。
{
    if(node[k].l>r||node[k].rr||node[k].r


 

你可能感兴趣的:(数据结构)