线段树(题集

 

 

扶苏学长给我们讲了线段树、树状数组、主席树等数据结构

并发布了练习题单……

 

题目:

 

A:

只需将maketag函数更改为异或和即可

然后tag的更新方式更改

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const long long  k=5e5+5;

long long  a[k];

struct Segment{
    long long  l,r;
    long long  sum;
    long long  tag;
    Segment *lef,*rig;
    
    Segment(const long long  L,const long long  R )
    {
        l=L;r=R;
        tag=0;
        if(l != r)
        {
            int mid=l+r>>1;
            lef=new Segment(l,mid);
            rig=new Segment(mid+1,r);
            sum=lef->sum +rig->sum ;
            tag=0;
        }
        else{
            lef=rig=NULL;
            sum=a[l];
        }
    }
    
    inline void maketag(){
        sum=(r-l+1)-sum;
        tag^=1;
    }
    
    void spread()
    {
//        if(lef == NULL) lef=new Segment(l,mid);
//        if(rig == NULL) rig =new Segment(mid+1,r);
        if(tag==0) return;
        else {
            lef->maketag();
            rig->maketag();
            tag=0;
        }
    }    

    inline bool Out(const long long  L,const long long  R) { return (R<l || r<L ) ;}

    void change(long long  L,long long  R)
    {
        if(L<=l && r<=R){
            maketag();
        }
        else {
            if(Out(L,R)) return ;
            else{
            spread();
            lef->change(L,R);
            rig->change(L,R);
            sum=lef->sum+rig->sum;
            } 
            
        }
    }
    
    
    long long  ask(long long  L,long long  R)
    {
        if(L<=l && r<=R) return sum;
        else {
            if(Out(L,R)) return 0;
            else{
            spread();
            return lef->ask(L,R)+rig->ask(L,R);
            
            } 
            
        }
    }
    
};

Segment *root;

int  main(void)
{
    long long  n,m,q;
    string str;
    
    ios_base::sync_with_stdio(false);
    cout.tie(NULL);
    cin.tie(NULL);
    
    cin>>n>>m;
    
    cin>>str;
    
    for(long long  i=1;i<=n;i++)
    {
        int q=str[i-1]-'0';
        a[i]=q;
    }
    
    root=new Segment(1,n);
    
    for(long long  i=1;i<=m;i++)
    {
        long long  x,y,z,g;
        cin>>x>>y>>z;
        
        if(x==0){
            root->change(y,z);
        }
        else {
            cout<<root->ask(y,z)<<'\n';
        }
    }
}

 

B、D:

模板不多说

 

C:
该题没有修改,只有询问,所以只维护一个最小值即可

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const long long  k=5e5+5;

long long  a[k];

struct Segment{
    long long  l,r;
    long long  sum;
    long long  tag;
    Segment *lef,*rig;
    
    Segment(const long long  L,const long long  R )
    {
        l=L;r=R;
        tag=0;
        if(l != r)
        {
            int mid=l+r>>1;
            lef=new Segment(l,mid);
            rig=new Segment(mid+1,r);
            sum=min(lef->sum,rig->sum);
            tag=0;
        }
        else{
            lef=rig=NULL;
            sum=a[l];
        }
    }
    inline bool Out(const long long  L,const long long  R) { return (R<l || r<L ) ;}


    long long  ask(long long  L,long long  R)
    {
        if(L<=l && r<=R) return sum;
        else {
            if(Out(L,R)) return 1<<30;
            else{
            return  min(lef->ask(L,R),rig->ask(L,R));
            
            } 
            
        }
    }
    
};

Segment *root;

int  main(void)
{
    long long  n,m,q;
    
    ios_base::sync_with_stdio(false);
    cout.tie(NULL);
    cin.tie(NULL);
    
    cin>>n>>m;
    
    for(int i=1;i<=n;i++)
    cin>>a[i];
    
    root=new Segment(1,n);
    
    for(long long  i=1;i<=m;i++)
    {
        long long  x,y,z;
        cin>>x>>y;
    
        cout<<root->ask(x,y)<<" ";
    }
}

 

 

F:

维护一个区间和与一个区间平方和

再对方差公式进行推导

即可

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cmath>
  6 using namespace std;
  7 const int maxn=100005;
  8 double a[maxn];
  9 int n,q;
 10 struct Node{
 11     double v1,v2,tag;
 12     int l,r;
 13     Node *ls,*rs;
 14     Node(const int L,const int R){
 15         l=L,r=R;
 16         if(l==r){
 17             tag=0;
 18             v1=a[l];
 19             v2=a[l]*a[l];//v2表示序列平方和,初始化为平方 
 20             rs=ls=NULL;
 21         }
 22         else{
 23             tag=0;
 24             int M=(L+R)>>1;
 25             ls=new Node(L,M);
 26             rs=new Node(M+1,R);
 27             pushup();
 28         }
 29     }
 30     inline void pushup(){
 31         v1=ls->v1+rs->v1;
 32         v2=ls->v2+rs->v2;
 33     }
 34     inline void pushdown(){
 35         if(tag==0) return;
 36         else{
 37             ls->maketag(tag);
 38             rs->maketag(tag);
 39             tag=0;
 40         }
 41     }
 42     inline void maketag(double w){
 43         v2=v2+(r-l+1)*w*w+2*w*v1;//根据公式计算,注意一定要先更新v2再更新v1,因为更新v2要用到原序列的和 
 44         v1+=(r-l+1)*w;
 45         tag+=w;
 46     }
 47     inline bool InRange(const int L,const int R){
 48         return (l>=L)&&(r<=R);
 49     }
 50     inline bool OutofRange(const int L,const int R){
 51         return (l>R)||(r<L);
 52     }
 53     inline void upd(const int L,const int R,double w){
 54         if(InRange(L,R)){
 55             maketag(w);
 56         }else if(!OutofRange(L,R)){
 57             pushdown();
 58             ls->upd(L,R,w);
 59             rs->upd(L,R,w);
 60             pushup();
 61         }
 62     }
 63     double qry(const int L,const int R){
 64         if(InRange(L,R)){
 65             return v1;
 66         }
 67         if(OutofRange(L,R)){
 68             return 0;
 69         }
 70         else{
 71             pushdown();
 72             return ls->qry(L,R)+rs->qry(L,R);
 73         }
 74     }
 75     double qry1(const int L,const int R){
 76         if(InRange(L,R)){
 77             return v2;
 78         }
 79         if(OutofRange(L,R)){
 80             return 0;
 81         }
 82         else{
 83             pushdown();
 84             return ls->qry1(L,R)+rs->qry1(L,R);
 85         }
 86     }
 87 };
 88 int main()
 89 {
 90     scanf("%d%d",&n,&q);
 91     for(int i=1;i<=n;i++){
 92         scanf("%lf",a+i);
 93     }
 94     Node *rot=new Node(1,n);
 95     for(int i=1;i<=q;i++){
 96         int o,x,y;
 97         double z;
 98         scanf("%lld%d%d",&o,&x,&y);
 99         if(x>y){
100             swap(x,y);
101         }
102         if(o==1){
103             scanf("%lf",&z);
104             rot->upd(x,y,z);
105         }
106         if(o==2){
107             printf("%.4lf\n",(rot->qry(x,y))/(y-x+1));
108         }
109         if(o==3){
110             double s1=rot->qry1(x,y);//平方和 
111             double s2=(rot->qry(x,y))/(y-x+1);//平均数
112             double s3=rot->qry(x,y);//
113             printf("%.4lf\n",((s1-2*s2*s3+(y-x+1)*s2*s2)/(y-x+1)));//根据公式计算 
114         }
115     }
116     return 0;
117 }

 

G:

多次试验表明,我煎不出来。。。

等扶苏学长来讲吧

 

H:

本题需要使用状压优化与位运算

初始时将所有颜色用二进制数表示

每次上色将对应的数值更新

下传标记为直接覆盖

上传信息时,将两个数进行或运算

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cmath>
  4 #include<ctime>
  5 #include<cstring>
  6 #include<iostream>
  7 #include<algorithm>
  8  
  9 using namespace std;
 10  
 11 int l, t, o, lf, rt, color;
 12 char op;
 13  
 14 struct Node{
 15     int l, r;
 16     long long tag, v;
 17     Node *ls, *rs;
 18      
 19     inline bool InRange(const int L, const int R){
 20         return (L <= l) && (r <= R);
 21     }
 22     inline bool OutofRange(const int L, const int R){
 23         return (L > r) || (l > R);
 24     } 
 25     inline void maketag(const long long x){
 26         tag = x;//????????????????? 
 27         v = x;//?????? 
 28     }
 29     inline void pushdown(){
 30         if(tag == 0)    return;//?????????????У????????′????????? 
 31         ls->maketag(tag);
 32         rs->maketag(tag);
 33         tag = 0;
 34     }
 35     inline void pushup(){
 36         /*if(ls != NULL){
 37             v |= ls->v;
 38         }
 39         if(rs != NULL){
 40             v |= rs->v;
 41         }*/
 42         v = (ls->v) | (rs->v);
 43     }
 44     Node (const int L, const int R){
 45         l = L;
 46         r = R; 
 47         tag = 0;
 48         if(L == R){
 49             tag = 0;
 50             v = 1 << 1;
 51             ls = NULL;
 52             rs = NULL;
 53         }
 54         else {
 55             int M = (l + r) >> 1;
 56             ls = new Node(l, M);
 57             rs = new Node(M + 1, R);
 58             pushup();
 59         }
 60     }
 61     inline void upd(const int L, const int R, const long long x){
 62         if(InRange(L, R)){
 63             maketag(x);
 64         }
 65         else if(!OutofRange(L, R)){
 66             pushdown();
 67             ls->upd(L, R, x);
 68             rs->upd(L, R, x);
 69             pushup(); 
 70         }
 71     }
 72     inline long long query(const int L, const int R){
 73         if(InRange(L, R)){
 74             return v;
 75         }
 76         else if(!OutofRange(L, R)){
 77             pushdown();
 78             return ls->query(L, R) | rs->query(L, R);
 79         }
 80         else return 0;
 81     }
 82 };
 83  
 84 inline int bit(const long long n){
 85     int res = 0, n0 = n;
 86     while(n0){
 87         res += (n0 & 1);
 88         n0 >>= 1;
 89     }
 90     return res;
 91 }
 92  
 93 int main(){
 94     scanf("%d%d%d",&l,&t,&o);
 95     Node *rot = new Node(1,l);
 96      
 97     for(int i=1;i<=o;i++){
 98         cin >> op;
 99         if(op == 'C'){
100             scanf("%d%d%d",&lf,&rt,&color);
101             if(lf > rt)  swap(lf, rt);
102             rot->upd(lf,rt,(long long)1<<color);
103         }
104         else{
105             scanf("%d%d",&lf,&rt);
106             if(lf > rt)  swap(lf, rt);
107             printf("%d\n",bit(rot->query(lf,rt)));
108         } 
109     }
110      
111     return 0;
112 }

 

I、J:

这两个题mod做

 

E将会在树状数组时进行讲解

另:《棠梨煎雪》可以通过树状数组拿到可观的部分分

 

-end-

 

posted @ 2020-07-05 17:01  ·Iris  阅读(223)  评论(2编辑  收藏  举报