您的位置:首页 > 运维架构

HDOJ 4578/2013年杭州邀请赛C题 - Transformation 线段树...比较蛋疼的维护PushDown

2013-08-11 18:22 411 查看
题意:

很裸.......

题解:

因为要统计3个次方...构造三颗线段树(同时更新查询)sum[1][MAXN]为一次方...sum[2][MAXN]为二次方..sum[3][MAXN]为三次方..

首先看如何更新...令[l,r]长度为len最容易的是区间[l,r]复制相为c...sum[1][now]=len*c

sum[2][now]=len*c*c

sum[3][now]=len*c*c*c

区间[l,r]乘c也容易: sum[1][now]=sum[1][now]*c

sum[2][now]=sum[2][now]*c*c

sum[3][now]=sum[3][now]*c*c*c

区间求和.. 先sum[3][now]...因为(a+c)^3=a^3+3a^a*c+3*a*c^2+c^3.则sum[3][now]=sum[3][now]+3*sum[2][now]*c+3*c*c*sum[1][now]+c*c*c*len

再sum[2]][now] 因为(a+c)^2=a^2+2ac+c^2..则sum[2][now]=sum[2][now]+2*sum[1][now]*c+c*c *len

最后 sum[1][now]..直接sum[1][now]=sum[1][now]+len*c

这些都比较简单....关键是维护懒惰标记...有三个操作..对于每个点就有三个懒惰标记来维护...但是操作间是有顺序的..比如先做了+/*运算..后面来个赋值运算..前面的运算就不做效了..又现做乘法再做加法和先做加法再做乘法..结果是完全不同的...我的解决办法是定了一个运算顺序..推进懒惰标记时..先处理赋值运算..再处理乘法运算..最后处理加法运算..在更新懒惰标记时..也保持这种顺序运算的正确性..


Program:

#include<iostream>
#include<stdio.h>
#include<cmath>
#include<queue>
#include<stack>
#include<string.h>
#include<map>
#include<set>
#include<algorithm>
#define oo 10007
#define MAXN 100005
#define ll int
using namespace std;
ll sum[4][MAXN<<2],col[4][MAXN<<2]; // 1+ 2* 3=
bool need[MAXN<<2];
void up(int tp,int len,ll c,int now)
{    
       if (tp==1)
       {
               sum[3][now]=(sum[3][now]+3*sum[2][now]%oo*c%oo+3*sum[1][now]%oo*c%oo*c%oo+c*c%oo*c%oo*len%oo)%oo;
               sum[2][now]=(sum[2][now]+2*c%oo*sum[1][now]%oo+c*c%oo*len%oo)%oo; 
               sum[1][now]=(sum[1][now]+c*len)%oo; 
       }else              
       if (tp==2)
       {
               sum[1][now]=sum[1][now]*c%oo;
               sum[2][now]=c*c%oo*sum[2][now]%oo;
               sum[3][now]=c*c%oo*c%oo*sum[3][now]%oo; 
       }else
       if (tp==3)
       {
               sum[1][now]=c*len%oo;
               sum[2][now]=c*c%oo*len%oo;
               sum[3][now]=c*c%oo*c%oo*len%oo;
       }
}
void PushDown(int len,int now) // 先覆盖..再乘..再加 
{
       if (!need[now]) return;
       need[now]=false,need[now<<1]=need[now<<1|1]=true;
       if (col[3][now]) 
       {
               up(3,len-(len>>1),col[3][now],now<<1);
               up(3,len>>1,col[3][now],now<<1|1);
               col[3][now<<1]=col[3][now<<1|1]=col[3][now];
               col[1][now<<1]=col[1][now<<1|1]=col[1][now];
               col[2][now<<1]=col[2][now<<1|1]=col[2][now];
       }else
       {
               col[2][now<<1]=(col[2][now<<1]*col[2][now])%oo;
               col[2][now<<1|1]=col[2][now<<1|1]*col[2][now]%oo; 
               col[1][now<<1]=(col[1][now<<1]*col[2][now]+col[1][now])%oo,
               col[1][now<<1|1]=(col[1][now<<1|1]*col[2][now]+col[1][now])%oo;               
       }
       up(2,len-(len>>1),col[2][now],now<<1),up(2,len>>1,col[2][now],now<<1|1);
       up(1,len-(len>>1),col[1][now],now<<1),up(1,len>>1,col[1][now],now<<1|1);  
       col[3][now]=col[1][now]=0,col[2][now]=1; 
       return;
}
void update(int L,int R,ll c,int tp,int l,int r,int now)
{
       if (L<=l && R>=r)
       {
               up(tp,r-l+1,c,now); 
               need[now]=true;
               if (tp==3) col[1][now]=0,col[2][now]=1,col[3][now]=c;
               else
               if (tp==2)
               {   
                      col[1][now]=col[1][now]*c%oo,
                      col[2][now]=col[2][now]*c%oo; 
               }else
               if (tp==1)  col[1][now]=(col[1][now]+c)%oo;
               return;
       }
       PushDown(r-l+1,now);
       int mid=(l+r)>>1;
       if (L<=mid) update(L,R,c,tp,l,mid,now<<1);
       if (R>mid)  update(L,R,c,tp,mid+1,r,now<<1|1);
       sum[1][now]=(sum[1][now<<1]+sum[1][now<<1|1])%oo;
       sum[2][now]=(sum[2][now<<1]+sum[2][now<<1|1])%oo;
       sum[3][now]=(sum[3][now<<1]+sum[3][now<<1|1])%oo;
       return;
}
ll query(int L,int R,int tp,int l,int r,int now)
{ 
       if (L<=l && R>=r) return sum[tp][now];
       PushDown(r-l+1,now);
       int mid=(l+r)>>1;
       ll ans=0;
       if (L<=mid) ans+=query(L,R,tp,l,mid,now<<1);
       if (R>mid)  ans+=query(L,R,tp,mid+1,r,now<<1|1);
       return ans%oo;            
}
int main()
{
       int n,m; 
       while (~scanf("%d%d",&n,&m) && (n || m))
       {
                memset(sum,0,sizeof(sum));
                memset(col,0,sizeof(col));  
                for (int i=0;i<(MAXN<<2);i++) col[2][i]=1;
                memset(need,false,sizeof(need));
                int tp,l,r,p;
                while (m--)
                {
                        scanf("%d%d%d%d",&tp,&l,&r,&p);
                        if (tp<4) update(l,r,p,tp,1,n,1);
                        else printf("%d\n",query(l,r,p,1,n,1));
                } 
       }
       return 0;
}
/*
13 4
1 1 4 6988
4 1 3 1
2 1 13 640
4 1 3 1
15 3
1 1 12 10 
3 1 15 2
4 1 4 1
78 4
1 1 44 7815
2 1 20 542
3 1 47 1
4 1 36 1
0 0
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: