• 9.3洛谷数据结构2


    P 4513  单点修改

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cctype>
    #define ll long long
    #define INF 0x3fffff
    #define clr(x) memset(x,0,sizeof(x))
    
    using namespace std;
    
    inline int read()
    {
        register int ret=0,c=getchar(),b=1;
        while(!isdigit(c))b=c=='-'?-1:1,c=getchar();
        while(isdigit(c))ret=ret*10+c-'0',c=getchar();
        return ret*b;
    }
    
    #define M 100005
    
    struct tree2
    {
        tree2 *lson,*rson;
        ll x,lazy;
    }dizhi[M<<1],*root=&dizhi[0];
    
    int n,m,t=1,a[M];
    
    void bulid(tree2 *tree,int l,int r)
    {
        if(l==r)
        {
            tree->x=a[l];
            return ;
        }
        int mid=(l+r)>>1;
        tree->lson=&dizhi[t++];
        tree->rson=&dizhi[t++];
        bulid(tree->lson,l,mid);
        bulid(tree->rson,mid+1,r);
        tree->x=tree->lson->x+tree->rson->x;
    }
    
    void pushdown(tree2 *tree,int l,int r)
    {
        if(!tree->lazy)return ;
        int mid=(l+r)>>1;
        tree->lson->x+=tree->lazy*(mid-l+1);
        tree->rson->x+=tree->lazy*(r-mid);
        tree->lson->lazy+=tree->lazy;
        tree->rson->lazy+=tree->lazy;
        tree->lazy=0;
    }
    
    void change(tree2 *tree,int l,int r,int x,int y,int d)
    {
        if(x<=l&&y>=r)
        {
            tree->x+=(ll)d*(r-l+1);
            tree->lazy+=d;
            return ;
        }
        pushdown(tree,l,r);
        int mid=(l+r)>>1;
        if(x<=mid)change(tree->lson,l,mid,x,y,d);
        if(y>mid) change(tree->rson,mid+1,r,x,y,d);
        tree->x=tree->lson->x+tree->rson->x;
    }
    
    ll query(tree2 *tree,int l,int r,int x,int y)
    {
        if(x<=l&&y>=r)
            return tree->x;
        pushdown(tree,l,r);
        int mid=(l+r)>>1;
        ll t1=0,t2=0;
        if(x<=mid)t1=query(tree->lson,l,mid,x,y);
        if(y>mid)t2=query(tree->rson,mid+1,r,x,y);
        return t1+t2;
    }
    
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;i++)
            a[i]=read();
        bulid(root,1,n);
        for(int i=1;i<=m;i++)
        {
            int mode=read();
            if(mode==1)
            {
                int a=read(),b=read(),c=read();
                change(root,1,n,a,b,c);
            }
            else
            {
                int a=read(),b=read();
                printf("%lld
    ",query(root,1,n,a,b));
            }
        }

     

    ST表

    算法用途

    Sparse Table,又称ST表,稀疏表。运用倍增的思想,可以解决RMQ,LCA等问题。其优点是在线查询。预处理复杂度为O(nlogn),查询复杂度为O(1)。

    算法思想

    运用倍增的思想,num[i][j]表示区间[i,i+(1<<

    j)]的值。然后进行预处理求出num数组。

    算法实现

    以求最大值为例

    ① 对于预处理,有如下转移方程式:

    num[i][j]=max(num[i][j-1],num[i+(1<<j-1)][j-1]);
    • 1

    这是什么东西啊??

    我们来推一遍:
    其实只是把[i,i+(1<<

    j)]这个区间给分成两块,一块是[i,i+(1<<j-1)],另一块是[i+(1<<j-1),i+(1<<j)](i+(1<<j)==i+(1<<j-1)+(1<<

    j-1))。

    所以这个区间的最大值就是这两个区间的最大值的较大者。

    然后就推好啦!

    ② 对于查询[x,y]之间的最大值,我们可以这样:

    int j=log2(y-x+1);
    printf("%d
    ",max(num[x][j],num[y-(1<<j)+1][j]));

    这又是什么东西??

    我们再来推一遍:
    num[x][j]表示[x,x+(1<<

    j)]这段区间,本来是刚好的,但是因为j是向下取整的,因此不一定取得完。取到的区间长度实际为1<<j-1。此时我们可以从y-(1<<j-1)=y-(1<<j)+1这个点开始取(取重了也没事),取相同的长度。然后在这两者之间取较大者即可。

    P3865

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define MAXN 150000
    using namespace std;
    int n,m;
    int num[MAXN+5][18];
    inline char readc(){
        static char buf[100000],*l=buf,*r=buf;
        if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
        if (l==r) return EOF;
        return *l++;
    }
    int _read(){
        int num=0; char ch=readc();
        while (ch<'0'||ch>'9') ch=readc();
        while (ch>='0'&&ch<='9'){ num=num*10+ch-48; ch=readc(); }
        return num;
    }
    void make(){
        for (int i=1;i<18;i++)
            for (int j=1;j+(1<<i)-1<=n;j++)
                num[j][i]=max(num[j][i-1],num[j+(1<<i-1)][i-1]);
    }
    int main(){
        n=_read(); m=_read();
        for (int i=1;i<=n;i++)
            num[i][0]=_read();
        make();
        for (int i=1;i<=m;i++){
            int x=_read(),y=_read();
            int j=log2(y-x+1);
            printf("%d
    ",max(num[x][j],num[y-(1<<j)+1][j]));
        }
        return 0;
    }

    线段树  扫描线

    hdu1542 

    /*
    1.保存矩形的上下边界,并且重要的,记录他们是属于上还是下,然后按高度升序排序
    2.保存竖线坐标,并且去重,是为了离散化
    3.以保存的上下边界数组去更新
    */
    #include <cstdio>
    #include <cstring>
    #include<iostream>
    #include <algorithm>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define MAX 110
    #define LCH(i) ((i)<<1)
    #define RCH(i) ((i)<<1 | 1)
    
    struct segment //保存矩形上下边界
    {
      double l,r,h; //左右横坐标,纵坐标
      int f; //-1为下边界,1为上边界
    }ss[2*MAX];
    struct node //线段树节点
    {
      int l,r;
      int cnt; //该节点被覆盖的情况
      double len; //该区间被覆盖的总长度
      int mid()
      { return (l+r)>>1; }
    }tt[2*MAX*4];
    double pos[2*MAX];
    int nums;
    
    int cmp(struct segment a ,struct segment b)
    {
      return a.h<b.h;
    }
    
    void build(int a, int b ,int rt)
    {
     tt[rt].l=a; tt[rt].r=b; tt[rt].cnt=0; tt[rt].len=0;
     if(a==b) return ;
     int mid=tt[rt].mid();
     build(a,mid,LCH(rt));
     build(mid+1,b,RCH(rt));
    }
    
    int binary(double key ,int low, int high)
    {
       while(low<=high)
       {
          int mid=(low+high)>>1;
          if(pos[mid] == key) return mid;
          else if(key < pos[mid]) high=mid-1;
          else                    low=mid+1;
       }
       return -1;
    }
    
    void get_len(int rt)
    {
       if(tt[rt].cnt) //非0,已经被整段覆盖
          tt[rt].len = pos[tt[rt].r+1] - pos[tt[rt].l];
       else if(tt[rt].l == tt[rt].r) //已经不是一条线段
          tt[rt].len = 0;
       else //是一条线段但是又没有整段覆盖,那么只能从左右孩子的信息中获取
          tt[rt].len = tt[LCH(rt)].len + tt[RCH(rt)].len ;
    }
    
    void updata(int a, int b ,int val ,int rt)
    {
       if(tt[rt].l==a && tt[rt].r==b) //目标区间
       {
          tt[rt].cnt += val; //更新这个区间被覆盖的情况
          get_len(rt);  //更新这个区间被覆盖的总长度
          return ;
       }
       int mid=tt[rt].mid();
       if(b<=mid) //只访问左孩子
          updata(a,b,val,LCH(rt));
       else if(a>mid) //只访问有孩子
          updata(a,b,val,RCH(rt));
       else //左右都要访问
       {
          updata(a,mid,val,LCH(rt));
          updata(mid+1,b,val,RCH(rt));
       }
       get_len(rt); //计算该区间被覆盖的总长度
    }
    
    int main()
    {
      int Case=0;
      int n;
      while(scanf("%d",&n)!=EOF && n)
      {
        nums=0;
        for(int i=0; i<n; i++)
        {
          double x1,y1,x2,y2;
          scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
          ss[nums].l=x1;  ss[nums].r=x2; ss[nums].h=y1; ss[nums].f=1;
          //记录上边界的信息
          ss[nums+1].l=x1; ss[nums+1].r=x2; ss[nums+1].h=y2; ss[nums+1].f=-1;
          //记录下边界的信息
          pos[nums]=x1; pos[nums+1]=x2;
          //记录横坐标
          nums += 2;
    
        }
    
        sort(ss,ss+nums,cmp); //横线按纵坐标升序排序
        sort(pos,pos+nums); //横坐标升序排序
        //for(int i=0; i<nums; i++) printf("%.2lf %.2lf  %.2lf
    ",ss[i].l,ss[i].r,ss[i].h);
        int m=1;
        for(int i=1; i<nums; i++)
          if(pos[i]!=pos[i-1]) //去重
            pos[m++]=pos[i];
    
        build(0,m-1,1);  //离散化后的区间就是[0,m-1],以此建树
        double ans=0;
        for(int i=0; i<nums; i++) //拿出每条横线并且更新
        {
           int l=binary(ss[i].l,0,m-1);
           int r=binary(ss[i].r,0,m-1)-1;
           updata(l,r,ss[i].f,1); //用这条线段去更新
           ans += (ss[i+1].h-ss[i].h)*tt[1].len;
           //printf("%.2lf
    ",ans);
        }
        printf("Test case #%d
    ",++Case);
        printf("Total explored area: %.2f
    
    ",ans);
      }
      return 0;
    }

    P1904(离散化)

  • 相关阅读:
    mysql 数据库检查与修复的办法
    SECPATH透明模式下VLAN透传配置实例
    腾讯QQ所有的服务器
    AutoRuns 9.13 汉化版
    IP地址在数据库中的存储解决方案
    DNS智能解析 for windows 2003
    Windows Media Player ActiveX 控件参数
    删除nvidia右键菜单
    通过js控制cookies
    正确使用|(按位或)和||(逻辑或)
  • 原文地址:https://www.cnblogs.com/zyddd915/p/11455861.html
Copyright © 2020-2023  润新知