2018南京网络赛 G. Lpl and Energy-saving Lamps (线段树非递归实现)

线段树非递归实现。点修改下的区间查询。

注意预处理的时候要把一到十万的都进行处理一遍,因为输入的月份不一定在月份的个数之内。

#include <iostream>
#include <cstring>
using namespace std;
const int inf=1e5+7;
const int themax=2e9+10;
int arr[4*inf],moth[inf],arr1[inf];
int ans[inf][2];        //初始化的时候都是零。 
int N,NN,n,k;               //确定N的值。
int now=0; 

void CreatSegment()       //N是啥呢。                  
{
    N=1; while(N<n+2)N=N<<1;         //大于等于n+2,这一种条件就已经限定了上面的是很多元素的。 
    for( int i=1;i<=n;i++ )
        arr[i+N]=arr1[i];            //最大的数到了,n+N,这应该是下一层的开始的那个数。 
    arr[N]=themax;
    NN=N<<1;
    for(int i=n+N+1;i<=NN;i++)        
        arr[i]=themax;                //这样进行的初始化。  
    for(int i=N-1;i>0;i--)            //但是这里应该是    
        arr[i]=arr[i<<1] < arr[i<<1|1]?arr[i<<1]:arr[i<<1|1];   //应该是这样的。 
}
int Query()            //如何进行限定 。            
{
    int i=1;
    while( i<N ) 
    {
        if( arr[i<<1 ]<= now )   //通过顺序来操作罢了。zh            
        {
            i=i<<1;        
        }
        else
        {
            i=i<<1|1;
        }
    }             //说明下标是arr数组的下标。
    return i;

void alter(int i)    //i应该是下标。 修改。 
{
    while(i!=1)
    {
        i=i>>1;        
        arr[i]=arr[i<<1]<arr[i<<1|1]?arr[i<<1]:arr[i<<1|1];        //修改完毕。 
    }
}

int main()
{
    while(~scanf("%d %d",&n,&k))
    {
        memset(ans,0,sizeof(ans));
        now=0;
        for(int i=1;i<=n;i++)
            scanf("%d",&arr1[i]);  //对arr建立线段树。 
        CreatSegment();            //创建完成之后就是所谓的点修改了。 
        int mothnum;
        scanf("%d",&mothnum);    
        for(int i=1;i<=100000;i++)  //就是这里的原因啊, 
        {
            if(ans[i-1][0]==n)       //这里看一下吧。 
            {
                ans[i][0]=ans[i-1][0];
                ans[i][1]=ans[i-1][1];
                continue;
            }
            now=now+k;                //线段树创建完成之后。    
            if(now<arr[1])
            {
                ans[i][0]=ans[i-1][0];     
                ans[i][1]=now;
            }
            else                    //这里是重点。点修改下的区间查询。 
            {
                int w=-1;            //从这里开始。 
                x:
                w++; 
                int flag=Query();            //                                                                                
                // 之后就是进行判断是在左边还是在右边了。如果是偶数的话,
                now=now-arr[flag];
                if(w==0)           
                    ans[i][0]=ans[i-1][0]+1;
                else
                    ans[i][0]=ans[i][0]+1;
                ans[i][1]=now;                //进行更新。
                arr[flag]=themax;                          
                alter(flag);    
                 if( now>=arr[1] )                
                     goto x;                    //最后一点就是没有的时候如何退出吧。    
            }     
        }    
        for(int i=1;i<=mothnum;i++)
        {
            int abc;
            scanf("%d",&abc);
            printf("%d %d\n",ans[abc][0],ans[abc][1]);        
        }        
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_40799464/article/details/82755931