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;
    }
    
  • 相关阅读:
    www.insidesql.org
    kevinekline----------------- SQLSERVER MVP
    Sys.dm_os_wait_stats Sys.dm_performance_counters
    如何使用 DBCC MEMORYSTATUS 命令来监视 SQL Server 2005 中的内存使用情况
    VITAM POST MORTEM – ANALYZING DEADLOCKED SCHEDULERS MINI DUMP FROM SQL SERVER
    Cargo, Rust’s Package Manager
    建筑识图入门(初学者 入门)
    Tracing SQL Queries in Real Time for MySQL Databases using WinDbg and Basic Assembler Knowledge
    Microsoft SQL Server R Services
    The Rambling DBA: Jonathan Kehayias
  • 原文地址:https://www.cnblogs.com/santiego/p/11789177.html
Copyright © 2011-2022 走看看