zoukankan      html  css  js  c++  java
  • 列队 权值线段树

    列队 权值线段树

    有一个(n×m)的方阵,进行(q)次操作,每次将第((x,y))个学生出列,输出该学生的编号,并将队列先向左对齐,再向前对齐,最后把该学生放在空位((n,m))。

    神仙题。

    一直在想如何使一行队伍整体向左移动,向上移动,没想到可以用权值线段树搞。自己太蒻想不到这种操作啊。

    详细讲一下权值线段树具体实现操作。

    用权值线段树维护当前行学生出列的信息,区间维护出列学生个数,并在每行开一个vector记录后面加进来的学生编号。第(j)列学生出列,即在这颗权值线段树上将第(j)列学生原来的位置(+1),表示此下标位置学生出列,然后将其放进当前行的vector。查询当前行第(j)列学生时,我们在权值线段树上查询,像平衡树那样,参考区间已经出列学生的信息来找到还未出列的第(j)个学生此时的线段树下标,这里如果下标小于列数那么说明就是下标就是原列编号,否则说明当前行第(j)个是后面加入的学生,于是我们从vector里面找就好了。

    另外,不用担心出列vector里面的学生这种情况,因为出列学生时会在权值线段树上删除了这个学生,所以查询时不会查到这个已经被删除的学生。

    再看这道题本身,我们维护(n+1)棵权值线段树,前(n)棵维护前(n)列前(m-1)列的信息,第(n+1)棵单独维护第(m)列。出列时,对于第(m)列的点,我们直接对第(n+1)棵线段树操作;对于不是第(m)列的,我们对(x)行的线段树操作,再对第(m)列的第(x)行(即第(n+1)棵线段树)操作即可。

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #define ll long long
    using namespace std;
    inline int read(){
        char ch=getchar();int s=0;
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9') s=s*10+(ch^'0'), ch=getchar();
        return s;
    }
    int n,m,q,mxr;
    #define MAXN 300003
    #define MAXM MAXN*20
    int tre[MAXM],sl[MAXM],sr[MAXM],cnt;
    void change(int &x, int l, int r, int pos){
        if(x==0) x=++cnt;
        ++tre[x]; // 区间删除的学生个数+1
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) change(sl[x], l, mid, pos);
        else change(sr[x], mid+1, r, pos);
    }
    int query(int x, int l, int r, int k){
        if(l==r) return l;
        int mid=(l+r)>>1;
        int lsum=mid-l+1-tre[sl[x]]; // 左儿子区间实际存在的学生个数
        if(lsum>=k) return query(sl[x], l, mid, k);
        else return query(sr[x], mid+1, r, k-lsum);
    }
    int rot[MAXN];
    int rot_last_col;
    vector<ll> ext[MAXN+1];
    inline ll del_last_col(int x){
        int pos=query(rot_last_col, 1, mxr, x); // 找到实际第x个学生的下标
        change(rot_last_col, 1, mxr, pos);
        if(pos<=n) return (ll)pos*m;
        else return ext[n+1][pos-n-1];
    }
    inline ll del(int x, int y){
        int pos=query(rot[x], 1, mxr, y);
        change(rot[x], 1, mxr, pos);
        if(pos<=m-1) return (ll)(x-1)*m+pos;
        else return ext[x][pos-m];
    }
    int main(){
        n=read(),m=read(),q=read();
        mxr=max(n,m)+q;
        while(q--) {
            int x=read(),y=read();
            if(y==m){
                ll ans=del_last_col(x); // 删除最后一列的第x行
                ext[n+1].push_back(ans); // 将(x,y)放到位置(n,m)
                printf("%lld
    ", ans);
            }else{
                ll ans=del(x, y); // 删除第x行第y列
                ll ans2=del_last_col(x); // 删除最后一列的第x行
                ext[x].push_back(ans2);  // 将第x行最后一列的学生加入到第x行中
                ext[n+1].push_back(ans);  // 将(x,y)放到位置(n,m)
                printf("%lld
    ", ans);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    《Python数据挖掘入门与实践》高清中文版PDF+英文版+源码下载
    discuz 论坛配置 QQ/163 网易邮箱
    Discuz! X3 去掉内容图片提示下载方法(去除图片提示下载附件)
    HTTPS的建立过程(SSL建立安全会话的过程)
    前端开发之走进Vue.js
    优雅统计代码耗时的4种方法!
    Maven配置多个远程仓库的实现方法
    idea maven 一直报错“Could not transfer artifact ......(系统找不到指定的路径。)”
    IntelliJ IDEA为类和方法自动添加注释
    maven “mvn clean package”和“mvn clean install”有什么不同?
  • 原文地址:https://www.cnblogs.com/santiego/p/11789177.html
Copyright © 2011-2022 走看看