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;
}