题解 P3372 【【模板】线段树 1】(珂朵莉树解法)

这道题可以用珂朵莉树做,但是由于数据比较不随机,而我也没有手写一颗平衡树,所以就被卡掉了,只拿了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)。

扫描二维码关注公众号,回复: 3710499 查看本文章

然后把它拆掉,再合在一起。

在这个过程中我们就可以拿到迭代器。(干什么等会说)


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('\n');
102             }
103         }
104     }
105 
106 }
107 
108 using namespace Solve;
109 
110 int main(){
111     solve();
112 }

猜你喜欢

转载自www.cnblogs.com/ilverene/p/9846339.html