zoukankan      html  css  js  c++  java
  • 线段树(题集

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

    并发布了练习题单……

    题目:

    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)<<'
    ';
            }
        }
    }

    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
    ",(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
    ",((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
    ",bit(rot->query(lf,rt)));
    108         } 
    109     }
    110      
    111     return 0;
    112 }

    I、J:

    这两个题mod做

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

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

    -end-

  • 相关阅读:
    SpringCloud项目中使用Nacos作为配置中心
    SpringCloud项目中使用Nacos作为注册中心
    idea创建maven多模块Spring Boot项目
    Java代码中对IP进行白名单验证
    idea配置jdk
    win10配置jdk1.8环境变量
    shell 提示符样式设置
    整数转换成中文读法的字符串
    比较三段式软件版本号大小
    Windows7安装 nginx+php 后访问.php文件出现 “No input file specified.” 的解决办法
  • 原文地址:https://www.cnblogs.com/-Iris-/p/13246751.html
Copyright © 2011-2022 走看看