zoukankan      html  css  js  c++  java
  • [线段树]跳蚤

    题目描述

    NiroBC 姐姐奴役了一群跳蚤,并随时把它们丢到一台图灵机的纸带上。
    一开始,纸带上没有跳蚤,每一个时刻,NiroBC 姐姐可能做以下三个操作之一:

    1. 在位置x 放置一只每次向右(坐标增大方向)跳t 格的跳蚤。
    2. 命令所有跳蚤向右跳跃一次,跳跃的距离为各自的t。
    3. 给定区间[l,r],求该区间内跳蚤的个数。

    输入

    第一行一个正整数Q,表示操作个数。
    接下来Q 行,这Q 行中的第i 行含有若干个整数,描述第i 个操作。
    (1) 若第一个整数为1,则紧跟两个整数xi 和ti,表示在xi 的位置放置一只每次向右跳跃ti 格的跳蚤。
    (2) 若第一个整数为2,则命令所有跳蚤向右跳跃一次。
    (3) 若第一个整数为3,则紧跟两个整数li 和ri,你需要输出此时区间[li, ri]中跳蚤的数量。

    输出

    对于每一个3 号操作,输出一行一个整数,表示该询问的答案。

    题解

    ①对于步长大于200的跳蚤(大步长),最多跳500次就会出界,所以直接模拟,用树状数组维护跳蚤位置。复杂度O(500 * 1e5 * log(1e5))
    ②对于步长小于等于200的跳蚤(小步长),将这些跳蚤以步长t分类,对每个t建一颗线段树,以维护步长为t的跳蚤的起始位置。
    比如某个操作1是要在x处插入一个步长位t的跳蚤,而在此之前已经实施了times次操作2(即跳跃),则可等价为这个操作1是在最开始实施(即所有操作之前)要在x-t * times处插入一个步长为t的跳蚤。这样将所有步长为t的跳蚤都统一跳了times步,而起始位置都做了相应的等价转换。
    在查询[l,r]区间的小步长跳蚤个数时,若之前已实施times次操作2,则对步长t的跳蚤,相当于查询起始位置在[l-t * times,r-t * times]的跳蚤个数,并统计到答案里。复杂度O(200 * 1e5 * log(1e5))

    代码

    #include<bits/stdc++.h>
    #pragma GCC optimize(2)
    #pragma GCC optimize(3,"Ofast","inline")
    #define lowbit(x) x&(-x)
    using namespace std;
    const int n=1e5;
    
    int c[100005];
    inline void add(int pos,int val){
      for(int i=pos;i<=n;i+=lowbit(i)){
        c[i]+=val;
      }
    }
    inline int getsum(int pos){
      int ret=0;
      for(int i=pos;i>0;i-=lowbit(i)){
        ret+=c[i];
      }
      return ret;
    }
    pair<int,int> P[100005];
    int tot=0;
    
    int rt[205];
    struct Node{
      int l,r,sum;
    }node[3000005];
    int ls[3000005],rs[3000005];
    int id=0;
    inline int newNode(int l,int r){
      node[++id]=Node{l,r,0};
      return id;
    }
    
    void addval_to_point(int k,int pos,int val){
      if(node[k].l==node[k].r){
        node[k].sum+=val;
        return;
      }
      int mid=(node[k].l+node[k].r)>>1;
      if(pos<=mid){
        if(!ls[k]) ls[k]=newNode(node[k].l,mid);
        addval_to_point(ls[k],pos,val);
      }
      else{
        if(!rs[k]) rs[k]=newNode(mid+1,node[k].r);
        addval_to_point(rs[k],pos,val);
      }
      node[k].sum=node[ls[k]].sum+node[rs[k]].sum;
    }
    
    int ask_interval_sum(int k,int l,int r){
      if(!k) return 0;
      if(l<=node[k].l&&node[k].r<=r) return node[k].sum;
      int mid=(node[k].l+node[k].r)>>1;
      int ret=0;
      if(l<=mid) ret+=ask_interval_sum(ls[k],l,r);
      if(r>mid) ret+=ask_interval_sum(rs[k],l,r);
      return ret;
    }
    
    int main()
    {
        int q;scanf("%d",&q);
        int times=0;
        while(q--){
            int op;scanf("%d",&op);
            if(op==1){
                int x,t;scanf("%d%d",&x,&t);
                if(t>200){
                    P[++tot]=make_pair(x,t);
                    add(x,1);
                }
                else{
                    int pos=x-t*times;
                    if(!rt[t]) rt[t]=newNode(-t*100000,100000);
                    addval_to_point(rt[t],pos,1);
                }
            }
            else if(op==2){
                times++;
                int _tot=0;
                for(int i=1;i<=tot;++i){
                    int x=P[i].first,t=P[i].second;
                    add(x,-1);
                    if(x+t<=n){
                        add(x+t,1);
                        P[++_tot]=make_pair(x+t,t);
                    }
                }
                tot=_tot;
            }
            else{
                int l,r;scanf("%d%d",&l,&r);
                int ans=getsum(r)-getsum(l-1);
                for(int i=1;i<=200;++i){
                    ans+=ask_interval_sum(rt[i],l-i*times,r-i*times);
                }
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    bootstrap1
    vim格式化代码实际上就是 "缩进代码", 命令是等号=
    thinkphp如何一次性的上传多个文件,在文件域中可以多选?
    linux下, 再次遇到使用thinkphp的模板标签时,报错used undefined function ThinkTemplatesimplexml_load_string() 是因为没有安装 php-xml包
    再谈 Mysql解决中文乱码
    碳膜电阻+1N5408二极管?
    华为发布业界首套物联网网络建设方法论
    页面错误提示
    Linux下Redis服务器安装配置
    svn 强制用户添加注释 和 允许用户修改注释
  • 原文地址:https://www.cnblogs.com/lllxq/p/12634464.html
Copyright © 2011-2022 走看看