hdu-4578(线段树操作)

参照别的博客敲了一遍,下次自己a一遍。

#include 
#include
#include
using namespace std;
#define N 100005
#define lld long long int
const int mod=10007;
struct node
{
    int l,r;
    int same;//记录区间值是否相同,即是否被统一修改为某值
    lld add,mul;//记录乘和加
    lld v;//记录值相同区间各点的值
}tree[N*4];
void push_down(int l,int r,int root){//向下更新区间操作
    if(l==r) return;
    int mid=(l+r)>>1;
    if(tree[root].same){//如果区间各点值相同,向下传递
        tree[root].same=0;
        tree[root*2].same=tree[root*2+1].same=1;
        tree[root*2].v=tree[root*2+1].v=tree[root].v;
        tree[root*2].add=tree[root*2+1].add=0;
        tree[root*2].mul=tree[root*2+1].mul=1;
    }
    else{
        if(tree[root].add){//先向下更新加,因为乘的更新会影响加
            if(tree[root*2].same) tree[root*2].v=(tree[root*2].v+tree[root].add)%mod;
            else{
                push_down(l,mid,root*2);
                tree[root*2].add=(tree[root].add+tree[root*2].add)%mod;
            }
            if(tree[root*2+1].same) tree[root*2+1].v=(tree[root*2+1].v+tree[root].add)%mod;
            else{
                push_down(mid+1,r,root*2+1);
                tree[root*2+1].add=(tree[root].add+tree[root*2+1].add)%mod;
            }
            tree[root].add=0;
        }
        if(tree[root].mul>1){
                if(tree[root*2].same) tree[root*2].v=(tree[root*2].v*tree[root].mul)%mod;
                else{
                    push_down(l,mid,root*2);
                    tree[root*2].mul=(tree[root*2].mul*tree[root].mul)%mod;
                }
                if(tree[root*2+1].same) tree[root*2+1].v=(tree[root*2+1].v*tree[root].mul)%mod;
                else{
                    push_down(mid+1,r,root*2+1);
                    tree[root*2+1].mul=(tree[root*2+1].mul*tree[root].mul)%mod;
                }
            tree[root].mul=1;
            }
    }
}
void build(int l,int r,int root){
    tree[root].l=l;tree[root].r=r;
    tree[root].v=0;tree[root].same=0;
    tree[root].mul=1;tree[root].add=0;
    if(l==r){
        tree[root].same=1;
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,root*2);
    build(mid+1,r,root*2+1);
}
void update(int l,int r,int root,lld c,int op){
    if(tree[root].l>r||tree[root].r=l&&tree[root].r<=r){
        if(op==3){     //操作3直接覆盖
            tree[root].same=1;
            tree[root].v=c;
            tree[root].mul=1;
            tree[root].add=0;
        }else{
            if(tree[root].same){//找到值相同区间,直接修改
                if(op==1) tree[root].v=(tree[root].v+c)%mod;
                else tree[root].v=(tree[root].v*c)%mod;
            }
            else{//不同值区间,向下更新加乘操作,然后记录本次更新
                push_down(l,r,root);
                if(op==1) tree[root].add=(tree[root].add+c)%mod;
                else tree[root].mul=(tree[root].mul*c)%mod;
            }
        }
        return;
    }
    push_down(tree[root].l,tree[root].r,root);
    update(l,r,root*2,c,op);
    update(l,r,root*2+1,c,op);
}
lld query(int l,int r,int root,int p){
    if(l>tree[root].r||tree[root].l>r) return 0;
    if(tree[root].l>=l&&tree[root].r<=r){
        if(tree[root].same){
            lld x=1;
            while(p--){
                x=x*tree[root].v%mod;
            }
            return x*(tree[root].r-tree[root].l+1)%mod;
        }
    }
    push_down(tree[root].l,tree[root].r,root);
    return (query(l,r,root*2,p)+query(l,r,root*2+1,p))%mod;
}
int main()
{
    int n,m,x,y,z,q;
    while(scanf("%d%d",&n,&m)&&(n||m)){
            build(1,n,1);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&q,&x,&y,&z);
            if(q==4) printf("%I64d\n",query(x,y,1,z));
            else update(x,y,1,z,q);
        }
    }
    return 0;
}


你可能感兴趣的:(线段树)