poj4047(线段树+延迟更新)

来源:互联网 发布:js二级下拉菜单代码 编辑:程序博客网 时间:2024/05/22 14:03

//线段树延迟更新

//将连续相邻的k个数据的和看成一个元素,建立线段树;交换、替代两种操作都可以统一成加法操作

 

//-------加法

//若当前加法操作的区间和当前所在节点的左右区间相同,则只修改延迟标记adi,和当前区间的最大值sum;若不一致,才开始向下执行加法操作,同时修改最大值

 

//------查询

//若当前查询的区间和当前所在区间相同,则直接返回结果;若不一致,则向下执行加法操作,同时修改最大值

 

 

#include <cstdio>#include <cstring>#include <algorithm>#include<iostream>using namespace std;#define MAX 200009typedef  int ll;int min(int a,int b){ return a<b?a:b;}int max(int a,int b){ return a<b?b:a;}ll a[MAX],da[MAX],ans;struct node { ll left,right,add; ll sum;}tree[MAX*5];//*****************************************************//建立以left,right为左右边界,将数组da中元素存储在首地址从1开始的tree数组中int build( ll id, ll left, ll right ){ tree[id].add=0; tree[id].left = left; tree[id].right = right; if( left == right ) {  tree[id].sum = da[left];  return tree[id].sum; } else {  ll mid = ( left + right )>>1;     tree[id].sum=max(build( id <<1, left, mid ), build( id<<1|1, mid + 1, right ));  return tree[id].sum; }}//*****************************************************************void down(int id){ if(tree[id].left==tree[id].right)  return ; tree[id<<1].add+=tree[id].add; tree[id<<1|1].add+=tree[id].add; tree[id<<1].sum+=tree[id].add; tree[id<<1|1].sum+=tree[id].add; tree[id].add=0;    }//修改//****************************************************//对区间[left,right]内每个元素进行加adi操作void updata( ll id, ll left, ll right, ll adi){ if(tree[id].left==left&&tree[id].right==right) {  tree[id].add+=adi;  tree[id].sum+=adi;  return ; } else  {  if(tree[id].add!=0)  {   down(id);  }    ll mid=(tree[id].left+tree[id].right)>>1;  if(right<=mid)   updata(id<<1,left,right,adi);  else if(left>mid)   updata(id<<1|1,left,right,adi);  else  {   updata(id<<1,left,mid,adi);   updata(id<<1|1,mid+1,right,adi);  }  if(tree[id].left!=tree[id].right)   tree[id].sum=max(tree[id<<1].sum ,tree[id<<1|1].sum); }}//*****************************************************************//3.查询//*****************************************************//查询区间[left,right]的和int query(ll id, ll left, ll right){ if( tree[id].left==left&&tree[id].right== right) {  return tree[id].sum; } else {  if(tree[id].add!=0)  {   down(id);  }  ll mid = (tree[id].left+tree[id].right)>>1;  if(right<= mid )   return query( id <<1, left,right);  else if(left>mid  )   return query( id <<1|1,left, right);  return max( query( id <<1, left,mid) ,query( id<<1|1, mid+1,right )); }}//*****************************************************************int main(){ int n,m,k,i,j,t; cin>>t; while(t--) {  scanf("%d%d%d",&n,&m,&k);  for(i=1;i<=n;i++)  {   scanf("%d",&a[i]);   da[i]=0;  }    for(i=1;i<=k;i++)   da[1]+=a[i];    for(i=2;i<=n-k+1;i++)   da[i]=da[i-1]-a[i-1]+a[i+k-1];      build(1,1,n-k+1);  for(i=0;i<m;i++)  {   int op,x,y;   scanf("%d%d%d",&op,&x,&y);   if(0==op)//x处用y替换   {    updata(1,max(1,x-k+1),min(n-k+1,x),y-a[x]);    a[x]=y;   }   else if(1==op)//将x处和y处元素交换   {        if(x==y)    continue;    updata(1,max(1,x-k+1),min(n-k+1,x),a[y]-a[x]);    updata(1,max(1,y-k+1),min(n-k+1,y),a[x]-a[y]);    int temp=a[x];    a[x]=a[y];    a[y]=temp;   }   else if(2==op)//输出[x,y]区间中   {    ans=query(1,x,y-k+1);//min(y-k+1,n-k+1));    printf("%d\n",ans);   }  } } return 0;}


 

原创粉丝点击