• 列队 权值线段树


    列队 权值线段树

    有一个(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;
    }
    
  • 相关阅读:
    原创的java数据访问框架
    在ASP.NET中使用Session常见问题集锦
    Infragistics中WebGrid的MultiColumn Headers设计
    常用asp.net代码
    如何实现函数IF的嵌套超过七层?
    Microsoft® Visual Studio® 2005 Team Suite Service Pack 1
    ASP.NET中常用的文件上传下载方法
    ASP.NET 2.0:使用用户控件和定制的Web部件个人化你的门户网站
    office2007TW
    http://www.ydowns.com/download/53279.rar
  • 原文地址:https://www.cnblogs.com/santiego/p/11789177.html
Copyright © 2020-2023  润新知