啥叫线段树我觉得就不用写了,看一个板子吧 我线段树写得不好众所周知。。
题目链接
https://www.luogu.com.cn/problem/P3373
注意事项
来自洛谷的一道题,说是板子感觉好像跟那个行星序列差不多其实一样 , 但那道题我是边看着板子边打的,这次我决定自己打一下试试,于是我就凭着自己的感觉把线段树打了一遍,然后就是调试过程,这次调还好,没有什么特别大的问题,就是有一点引起了我的注意,pushdown的时候要不要进行更新,我当时想的是,pushdown完了儿子节点已经被更新,如果不更新一下父亲节点,就会出问题。
实际上不是的,pushdown的标记是哪来的?是更新完父亲节点后push下来的,所以应该是父亲节点已经更新而儿子节点未更新,所以要pushdown保证访问的是正确的儿子信息,而乍一想在pushdown里边修改父亲节点好像也不会出问题,没错只是乍一想,写了后在数据很大的情况下会直接RE为什么?因为有可能你更新的是叶子节点,这样的话叶子就会被更新成0所以不能在这里更新。再有就是这道题按老师讲的做法来做把我自己搞懵了,一会儿push乘法一会儿push加法。。。。。所以我觉得可以换一个写法,乘和加一块push,如果修改乘法,那不就是+0嘛,修改加法,那不就是×1嘛,所以直接放到一起就好,这道题最大的收获还是写对了线段树找点自信 感觉像数据结构这一类的东西不要背模板,背了也没啥用,到时候一紧张忘了就白扯,所以要靠自己的理解去记忆,这样大不了到时候打错了还能自己调。
1 #include2 #include 3 #include 4 #include 5 #define ll long long 6 using namespace std; 7 const int N=1e5+10; 8 struct Node{ 9 ll val,cheng,jia; 10 Node(){cheng=1;jia=0;} 11 }tree[N<<2]; 12 ll a[N],p; 13 void Build(ll rt,ll l,ll r){ 14 if(l==r){ 15 tree[rt].val=a[l]%p; 16 return; 17 } 18 ll mid=l+r>>1; 19 Build(rt<<1,l,mid); 20 Build(rt<<1|1,mid+1,r); 21 tree[rt].val=(tree[rt<<1].val+tree[rt<<1|1].val)%p; 22 } 23 ll cr,cl; 24 void updata(ll rt,ll l,ll r,ll w,ll k){ 25 tree[rt].val=(tree[rt].val*k%p+w*(r-l+1)%p)%p; 26 tree[rt].jia=(tree[rt].jia*k%p+w)%p; 27 tree[rt].cheng=tree[rt].cheng*k%p; 28 } 29 void pushdown(ll rt,ll l,ll r){ 30 ll mid=l+r>>1; 31 updata(rt<<1,l,mid,tree[rt].jia,tree[rt].cheng); 32 updata(rt<<1|1,mid+1,r,tree[rt].jia,tree[rt].cheng); 33 tree[rt].cheng=1;tree[rt].jia=0; 34 } 35 void modify(ll rt,ll l,ll r,ll w,ll k){ 36 if(cr r)return; 37 if(cr>=r&&cl<=l){ 38 updata(rt,l,r,w,k); 39 return; 40 } 41 pushdown(rt,l,r); 42 ll mid=l+r>>1; 43 modify(rt<<1,l,mid,w,k); 44 modify(rt<<1|1,mid+1,r,w,k); 45 tree[rt].val=(tree[rt<<1].val+tree[rt<<1|1].val)%p; 46 } 47 ll query(ll rt,ll l,ll r){ 48 if(l>=cl&&r<=cr){ 49 tree[rt].val%=p; 50 return tree[rt].val; 51 } 52 int mid=l+r>>1; 53 pushdown(rt,l,r); 54 ll ans=0; 55 if(cl<=mid)ans=(ans+query(rt<<1,l,mid))%p; 56 if(cr>mid)ans=(ans+query(rt<<1|1,mid+1,r))%p; 57 return ans; 58 } 59 int main(){ 60 int m,n; 61 scanf("%d%d%lld",&n,&m,&p); 62 for(int i=1;i<=n;i++) 63 scanf("%d",&a[i]); 64 Build(1,1,n); 65 for(int i=1;i<=m;i++){ 66 ll num,type; 67 scanf("%lld%lld%lld",&type,&cl,&cr); 68 if(type==1){ 69 scanf("%lld",&num); 70 modify(1,1,n,0,num); 71 } 72 else if(type==2){ 73 scanf("%lld",&num); 74 modify(1,1,n,num,1); 75 }else{ 76 printf("%lld\n",query(1,1,n)%p); 77 } 78 } 79 return 0; 80 }
依旧是不开long long见祖宗,开个longlong又不费时间,能开尽量就开,别最后再改,万一你最后忘了呢?而且写个ll还比int少写一个字符,好吧这是次要的