菜菜,帮帮

题目总版

dingxingjian @ 2024-11-29 16:34:26

感谢大佬的帮忙 题目是hdu4578,我的思路是线段树+懒修改,测试样例过了但一直wrong answer。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int mod=10007;
const int N = 1e5 + 10;
struct num{
    ll sum1=0,sum2=0,sum3=0;
}tree[N*4];
ll a[N]={0};        //记录数列的元素,从a[1]开始
ll tag1[N*4]={0},tag2[N*4]={1},tag3[N*4]={0};   //tag[i]:第i个结点的lazy-tag,统一记录这个区间的修改
ll ls(ll p){ return p<<1;  }           //定位左儿子:p*2
ll rs(ll p){ return p<<1|1;}           //定位右儿子:p*2 + 1
void push_up(ll p){                    //从下往上传递区间值
    tree[p].sum1 = (tree[ls(p)].sum1 + tree[rs(p)].sum1)%mod; 
    tree[p].sum2 = (tree[ls(p)].sum2 + tree[rs(p)].sum2)%mod; 
    tree[p].sum3 = (tree[ls(p)].sum3 + tree[rs(p)].sum3)%mod; 
     //本题是区间和。如果求最小值,改为:tree[p] = min(tree[ls(p)], tree[rs(p)]);
}
void addtag(int a,ll p,ll pl,ll pr,ll d){     //给结点p打tag标记,并更新tree
    /*tag[p] += d;                        //打上tag标记
    tree[p] += d*(pr-pl+1);*/             //计算新的tree
    ll sum1old=tree[p].sum1,sum2old=tree[p].sum2,sum3old=tree[p].sum3;
    if(a==3){
        tag1[p] = 0; tag2[p] = 1; tag3[p] = d;
        tree[p].sum1=(d*(pr-pl+1))%mod;
        tree[p].sum2=(d*d*(pr-pl+1))%mod;
        tree[p].sum3=(d*d*d*(pr-pl+1))%mod;
    }
    else if(a==1){
        tag1[p]=(tag1[p]+d)%mod;
        tree[p].sum1=(tree[p].sum1+d*(pr-pl+1))%mod;
        tree[p].sum2=(tree[p].sum2+d*d*(pr-pl+1)+2*d*sum1old)%mod;
        tree[p].sum3=(tree[p].sum3+d*d*d*(pr-pl+1)+3*d*d*sum1old+3*d*sum2old)%mod;
    }
    else if(a==2){
        tag2[p]*=d; tag1[p]*=d;
        tree[p].sum1=(tree[p].sum1*d)%mod;
        tree[p].sum2=(tree[p].sum2*d*d)%mod;
        tree[p].sum3=(tree[p].sum3*d*d*d)%mod;
    }
}
void push_down(ll p,ll pl,ll pr){       //不能覆盖时,把tag传给子树
    if(tag3[p]){                         //有tag标记,这是以前做区间修改时留下的
        ll mid = (pl+pr)>>1; 
        addtag(3,ls(p),pl,mid,tag3[p]);    //把tag标记传给左子树
        addtag(3,rs(p),mid+1,pr,tag3[p]);  //把tag标记传给右子树
        tag3[p]=0;                       //p自己的tag被传走了,归0
    }
    if(tag2[p]!=1){                         //有tag标记,这是以前做区间修改时留下的
        ll mid = (pl+pr)>>1; 
        addtag(2,ls(p),pl,mid,tag2[p]);    //把tag标记传给左子树
        addtag(2,rs(p),mid+1,pr,tag2[p]);  //把tag标记传给右子树
        tag2[p]=1;                       //p自己的tag被传走了,归0
    }
    if(tag1[p]){                         //有tag标记,这是以前做区间修改时留下的
        ll mid = (pl+pr)>>1; 
        addtag(1,ls(p),pl,mid,tag1[p]);    //把tag标记传给左子树
        addtag(1,rs(p),mid+1,pr,tag1[p]);  //把tag标记传给右子树
        tag1[p]=0;                       //p自己的tag被传走了,归0
    }
}
         //(   L,   R,   1,    1,   n,    d)
void update(int a,ll L,ll R,ll p,ll pl,ll pr,ll d){ //区间修改:把[L, R]内每个元素加上d
    if(L<=pl && pr<=R){       //完全覆盖,直接返回这个结点,它的子树不用再深入了    
        addtag(a,p, pl, pr,d);  //给结点p打tag标记,下一次区间修改到p时会用到
        return;                       
    }
    push_down(p,pl,pr);                 //如果不能覆盖,把tag传给子树
    ll mid=(pl+pr)>>1;
    if(L<=mid) update(a,L,R,ls(p),pl,mid,d);    //递归左子树
    if(R>mid)  update(a,L,R,rs(p),mid+1,pr,d);  //递归右子树
    push_up(p);                               //更新
}
ll query(int a,ll L,ll R,ll p,ll pl,ll pr){
  //查询区间[L,R];p是当前结点(线段)的编号,[pl,pr]是结点p表示的线段区间
    if(a==1){
        if(pl>=L && R >= pr) return tree[p].sum1;       //完全覆盖,直接返回
        push_down(p,pl,pr);                        //不能覆盖,递归子树
        ll res=0;
        ll mid = (pl+pr)>>1;
        if(L<=mid) res+=query(a,L,R,ls(p),pl,mid);   //左子结点有重叠
        if(R>mid)  res+=query(a,L,R,rs(p),mid+1,pr); //右子结点有重叠
        return res;
    }
    else if(a==2){
        if(pl>=L && R >= pr) return tree[p].sum2;       //完全覆盖,直接返回
        push_down(p,pl,pr);                        //不能覆盖,递归子树
        ll res=0;
        ll mid = (pl+pr)>>1;
        if(L<=mid) res+=query(a,L,R,ls(p),pl,mid);   //左子结点有重叠
        if(R>mid)  res+=query(a,L,R,rs(p),mid+1,pr); //右子结点有重叠
        return res;
    }
    else if(a==3){
        if(pl>=L && R >= pr) return tree[p].sum3;       //完全覆盖,直接返回
        push_down(p,pl,pr);                        //不能覆盖,递归子树
        ll res=0;
        ll mid = (pl+pr)>>1;
        if(L<=mid) res+=query(a,L,R,ls(p),pl,mid);   //左子结点有重叠
        if(R>mid)  res+=query(a,L,R,rs(p),mid+1,pr); //右子结点有重叠
        return res;
    }
}
int main(){
    ll n, m;  scanf("%lld%lld",&n,&m);                          //建树
    while(m--){
        ll q,L,R,d;     scanf("%lld %lld %lld %lld",&q,&L,&R,&d);
        if (q==1){update(1,L,R,1,1,n,d);}
        else if(q==2) {update(2,L,R,1,1,n,d);}
        else if(q==3) {update(3,L,R,1,1,n,d);}
        else if(q==4) {printf("%lld\n",query(d,L,R,1,1,n)%mod);}       
    }
    return 0;
}

|