列队题解以及注意事项

一道十分interesting的题目

这道题显然要使用数据结构维护。但是n的规模十分大。我们便可以开n棵线段树,动态开点。但是最后一列比较特殊,所以我们再开一棵线段树维护最后一列。至于怎么操作?我们考虑权值线段树。权值线段树一般是维护:权值为[L,r]的数有多少是满足某种条件的。本道题目中我们维护区间[L,R]中有多少个数没有操作过。线段树的长度要开为 max(n,m)+q,这样如果我们查询一个数的位置发现她超过了m,说明她已经不在原位置了,出去的数我们用vector存储,每次直接访问下标就可以查询了。这里的原理就是查询该行排名为k的点。发现这个点之后就将其压入维护最后一列的vector中,并将此时在最后一列中排名为K的点压入改行,就行了。注意特判询问的纵坐标为m的情况

code:

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cmath>
#include<set>
#include<cstring>
#include<vector> 
#define max MAX
#define maxn 5000006
#define mod 1000000007
#define rep(i,a,b) for (int i=a;i<=b;++i)
#define erep(i,a) for (int i=head[a];i!=-1;i=e[i].next)
#define half (l+r)>>1
#define lson t[s].lc
#define pb push_back
#define all (zmd)
#define rson t[s].rc
using namespace std;
#define int long long 

struct zmd
{
    int fx,fy;	
};
struct hzw
{
    int lc,rc,sum;
}t[maxn]; 
int n,m,mx,tot,q;
inline int MAX(int a,int b) {return a>b?a:b;}
inline void update(int &s,int l,int r,int p)
{
    if (!s) s=++tot;
    if (l==r)
    {
        t[s].sum++;
        return;	
    } 
    int mid=half;
    if (p<=mid) update(lson,l,mid,p);
    else update(rson,mid+1,r,p);
    t[s].sum=t[lson].sum+t[rson].sum;
}
int root[maxn];
inline int query(int s,int l,int r,int p)
{
    if (l==r) return l;
    int mid = half;
    int tmp=(mid-l+1) - t[lson].sum;
    if (p<=tmp) return query(lson,l,mid,p);
    else return query(rson,mid+1,r,p-tmp);
}
vector<zmd>v[300006];
inline int solve1(int x,int y)
{
    int now = query(root[x],1,mx,y),ans;
    update(root[x],1,mx,now); // take away
    if (now<m) 
    {
        ans=m*(x-1)+now; 
        v[n+1].pb(all{x,now}); //insert back
    }
    else 
    {
        zmd wow = v[x][now-m];
        ans=m*(wow.fx-1)+wow.fy;
        v[n+1].pb(wow);
    }	
    int bk = query(root[n+1],1,mx,x);
    update(root[n+1],1,mx,bk);
    if (bk<=n) v[x].pb(all{bk,m}); //no used is insert easily
    else {zmd wow = v[n+1][bk-n-1];v[x].pb(wow);} //find and insert now    
    return ans;   
}
inline int solve2(int x,int y)  // final insert
{
    int now=query(root[n+1],1,mx,x);
    update(root[n+1],1,mx,now);
    zmd wow;
    if (now<=n) wow.fx=now,wow.fy=m;
    else wow = v[n+1][now-n-1];
    v[n+1].pb(wow);  
    return m*(wow.fx-1)+wow.fy;
}
#undef int
int main()
{
    #define int long long 
    cin>>n>>m>>q;
    mx = max(n,m)+q;
    rep(i,1,q)
    {
        int a,b;
        scanf("%lld%lld",&a,&b);
        printf("%lld\n",b==m?solve2(a,b):solve1(a,b));
    }
    return 0;
}

注意事项:

define max(a,b) a>b?a:b 有时候会出玄学错误:例子:

看,十分玄妙,所以不要乱define了

posted @ 2018-11-01 17:10  Splitor  阅读(218)  评论(0编辑  收藏  举报