您的位置:首页 > 其它

poj 4047金华邀请赛 D题 (线段树+lazy优化)

2012-07-08 07:09 393 查看
/*题意:
给出一个N个数的序列以及一个k(0<k<=n<=200000),m个操作p,x,y,其中
p=0:将x位置的数替换为y
p=1:将x y位置的数互换
p=2: 查询x-y位置区间连续k个数的和的最大值

分析:因为要求连续区间的最大,我们可以把区间和当做一个节点,这样区间就代表一个点,点就代表一个区间了,这样就可以把原来1~n个数重新分为1~n-k+1了,所以我们只要建一颗总节点范围为1~n-k+1的线段树,p=0时,他能影响到的区间为[min(1,a-k+1),max(n-k+1,b),这个区间的最大值都变成了maxx+=b-v[a];p=1的类似。p=2时,询问的区间为
a~b-k+1;
最关键的就是线段树的优化,lazy操作。当前我的理解就是:更新的时候如果当前满足的要求,标记lazy,不在往下更新,当不符合要求的时候才继续往下update,并且更新子节点的时候回来必须更新父节点。询问的时候,当符合要求的时候就返回当父节点的值,不符合的时候才往下更新知道可以知道结果就停止了。这样就能达到了不需要更新的就不更新的效果,从而优化了。*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include<iostream>
using namespace std;
const int Nmax=200080;
int n,m,k,sum;
int v[Nmax];
int b[Nmax];
struct Node
{
    int L;
    int R;
    int maxx;
    int lazy;//父节点还没有释放的值
}tree[Nmax*10];

int builttree(int fa,int LL,int RR)//返回根的最大值
{
    int mid=(LL+RR)/2;
    tree[fa].L=LL;
    tree[fa].R=RR;
    tree[fa].lazy=0;
    if(LL==RR)
    {
        tree[fa].maxx=b[mid];
        return b[LL];
    }
    int t=builttree(fa*2,LL,mid);
    int r=builttree(fa*2+1,mid+1,RR);
    tree[fa].maxx=max(r,t);//父节点的最大值在建完子树之后才能求出
    return tree[fa].maxx;
}
void down(int fa)//向下更新
{
    if(tree[fa].L==tree[fa].R)
    return ;
    tree[fa*2].lazy+=tree[fa].lazy;
    tree[fa*2].maxx+=tree[fa].lazy;
    tree[fa*2+1].lazy+=tree[fa].lazy;
    tree[fa*2+1].maxx+=tree[fa].lazy;
    tree[fa].lazy=0;
}
void up(int fa)//向上更新
{
    if(tree[fa].L==tree[fa].R)return ;
    tree[fa].maxx=max(tree[fa*2].maxx,tree[fa*2+1].maxx);
}

void update(int fa,int LL,int RR,int val)
{
    if(tree[fa].L==LL&&tree[fa].R==RR)
    {
        tree[fa].maxx+=val;
        tree[fa].lazy+=val;
        return ;
    }
    if(tree[fa].lazy)
    down(fa);//父节点在上次中还没被向下释放的值
    int mid=(tree[fa].L+tree[fa].R)/2;
    if(RR<=mid)
    update(fa*2,LL,RR,val);
    else if(LL>mid)
    update(fa*2+1,LL,RR,val);
    else
    {
        update(fa*2,LL,mid,val);
        update(fa*2+1,mid+1,RR,val);
    }
    up(fa);//必须修改他父亲的值
}

int query(int fa,int LL,int RR)
{
    if(tree[fa].L==LL&&tree[fa].R==RR)
    return tree[fa].maxx;
    if(tree[fa].lazy)
    down(fa);
    int mid=(tree[fa].L+tree[fa].R)/2;

    if(RR<=mid)
      return query(fa*2,LL,RR);
    else if(LL>mid)
      return query(fa*2+1,LL,RR);
    else
    {
       int r= query(fa*2,LL,mid);
       int t= query(fa*2+1,mid+1,RR);
       return max(r,t);
    }
}

int main()
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        //cin>>n>>m>>k;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)
         //cin>>v[i];
         scanf("%d",&v[i]);
         sum=n-k+1;
         memset(b,0,sizeof(b));
        for(int i=1;i<=k;i++)
           b[1]+=v[i];

        for(int i=2;i<=n-k+1;i++)
        b[i]=b[i-1]-v[i-1]+v[i+k-1];
//        for(int i=1;i<=n;i++)
//        cout<<b[i]<<' ';
//        cout<<endl;
        int aa=builttree(1,1,n-k+1);
//        cout<<aa<<endl;
//        for(int i=1;i<=n;i++)
//        cout<<tree[i].maxx<<' ';
//        cout<<endl;
        int com;
        int a,b;
        for(int i=0;i<m;i++)
        {
          //cin>>com>>a>>b;
          scanf("%d%d%d",&com,&a,&b);
          if(com==0)
          {
            update(1,max(1,a-k+1),min(sum,a),b-v[a]);//注意区间,不要越b数组界
            v[a]=b;
          }
          else if(com==1)
          {
            update(1,max(1,a-k+1),min(a,sum),v[b]-v[a]);
            update(1,max(1,b-k+1),min(sum,b),v[a]-v[b]);
            swap(v[a],v[b]);
          }
          else if(com==2)
          {
              int ans=query(1,a,b-k+1);
              //cout<<ans<<endl;
              printf("%d\n",ans);
          }
        }
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: