这道题可以用珂朵莉树做,但是由于数据比较不随机,而我也没有手写一颗平衡树,所以就被卡掉了,只拿了70分。
珂朵莉树是一种基于平衡树的(伪)高效数据结构。
它的核心操作是推平一段区间。
简而言之,就是把之前的零零碎碎的都干掉,用一个美而饱满的大区间取代。
然后我们更新操作和查询操作就暴力遍历一遍,统计一下和就可以了。
Split操作
1 inline set<node>::iterator split(int pos){ 2 set<node>::iterator it=s.lower_bound(node(pos)); 3 if(it!=s.end()&&it->l==pos)return it; 4 --it; 5 int L=it->l,R=it->r;long long V=it->v; 6 s.erase(it),s.insert(node(L,pos-1,V)); 7 return s.insert(node(pos,R,V)).first; 8 }
split操作就是获得区间的迭代器。
所以我们要先找到pos在哪里(也就是it)。
然后把它拆掉,再合在一起。
在这个过程中我们就可以拿到迭代器。(干什么等会说)
Update操作
1 inline void update(int l,int r,long long val=1){ 2 set<node>::iterator itl=split(l),itr=split(r+1); 3 for(;itl!=itr;++itl)itl->v+=val; 4 }
现在刚才的split就派上用场了。
我们现在相当于是获得了区间的两端(也是区间)。
然后暴力遍历一下,给每个区间都打一个标记。
Query操作
1 inline long long query(int l,int r){ 2 set<node>::iterator itl=split(l),itr=split(r+1); 3 long long ans=0; 4 for(;itl!=itr;++itl)ans+=(itl->r-itl->l+1)*itl->v; 5 return ans; 6 }
收集一下标记加在一起就可以了,思路和update一样。
70分代码如下:
3741ms 2368kb
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 namespace StandardIO{ 6 7 template<typename T>inline void read(T& x){ 8 x=0;T f=1;char c=getchar(); 9 for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1; 10 for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0'; 11 x*=f; 12 } 13 14 template<typename T>inline void write(T x){ 15 if(x<0)putchar('-'),x*=-1; 16 if(x>=10)write(x/10); 17 putchar(x%10+'0'); 18 } 19 20 } 21 22 using namespace StandardIO; 23 24 namespace ChthollyTree{ 25 26 struct Tree{ 27 private: 28 struct node{ 29 int l,r;mutable long long v; 30 node(int L,int R=-1,long long V=0):l(L),r(R),v(V){} 31 bool operator < (const node &o)const{ 32 return l<o.l; 33 } 34 }; 35 set<node>s; 36 37 inline set<node>::iterator split(int pos){ 38 set<node>::iterator it=s.lower_bound(node(pos)); 39 if(it!=s.end()&&it->l==pos)return it; 40 --it; 41 int L=it->l,R=it->r;long long V=it->v; 42 s.erase(it),s.insert(node(L,pos-1,V)); 43 return s.insert(node(pos,R,V)).first; 44 } 45 46 inline void update(int l,int r,long long val=1){ 47 set<node>::iterator itl=split(l),itr=split(r+1); 48 for(;itl!=itr;++itl)itl->v+=val; 49 } 50 51 inline long long query(int l,int r){ 52 set<node>::iterator itl=split(l),itr=split(r+1); 53 long long ans=0; 54 for(;itl!=itr;++itl)ans+=(itl->r-itl->l+1)*itl->v; 55 return ans; 56 } 57 58 public: 59 Tree(){} 60 ~Tree(){} 61 62 inline void Init(int n){ 63 s.insert(node(1,n)); 64 } 65 66 inline void Update(int l,int r,long long val){ 67 update(l,r,val); 68 } 69 70 inline int Query(int l,int r){ 71 return query(l,r); 72 } 73 }; 74 75 } 76 77 using namespace ChthollyTree; 78 79 namespace Solve{ 80 81 const int N=100100; 82 83 int n,m; 84 int sum[N]; 85 Tree ljz; 86 87 inline void solve(){ 88 read(n),read(m); 89 ljz.Init(n); 90 for(register int i=1;i<=n;++i){ 91 int tmp;read(tmp); 92 sum[i]=sum[i-1]+tmp; 93 } 94 while(m--){ 95 int op,x,y,z; 96 read(op),read(x),read(y); 97 if(op==1){ 98 read(z); 99 ljz.Update(x,y,z); 100 }else{ 101 write(ljz.Query(x,y)+sum[y]-sum[x-1]),putchar(' '); 102 } 103 } 104 } 105 106 } 107 108 using namespace Solve; 109 110 int main(){ 111 solve(); 112 }