关于线段树的一些问题

啥叫线段树我觉得就不用写了,看一个板子吧  我线段树写得不好众所周知。。

题目链接

https://www.luogu.com.cn/problem/P3373

注意事项

来自洛谷的一道题,说是板子感觉好像跟那个行星序列差不多其实一样 , 但那道题我是边看着板子边打的,这次我决定自己打一下试试,于是我就凭着自己的感觉把线段树打了一遍,然后就是调试过程,这次调还好,没有什么特别大的问题,就是有一点引起了我的注意,pushdown的时候要不要进行更新,我当时想的是,pushdown完了儿子节点已经被更新,如果不更新一下父亲节点,就会出问题。

实际上不是的,pushdown的标记是哪来的?是更新完父亲节点后push下来的,所以应该是父亲节点已经更新而儿子节点未更新,所以要pushdown保证访问的是正确的儿子信息,而乍一想在pushdown里边修改父亲节点好像也不会出问题,没错只是乍一想,写了后在数据很大的情况下会直接RE为什么?因为有可能你更新的是叶子节点,这样的话叶子就会被更新成0所以不能在这里更新。再有就是这道题按老师讲的做法来做把我自己搞懵了,一会儿push乘法一会儿push加法。。。。。所以我觉得可以换一个写法,乘和加一块push,如果修改乘法,那不就是+0嘛,修改加法,那不就是×1嘛,所以直接放到一起就好,这道题最大的收获还是写对了线段树找点自信 感觉像数据结构这一类的东西不要背模板,背了也没啥用,到时候一紧张忘了就白扯,所以要靠自己的理解去记忆,这样大不了到时候打错了还能自己调。

 1 #include
 2 #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(crr)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少写一个字符,好吧这是次要的

你可能感兴趣的:(关于线段树的一些问题)