1. 程式人生 > >列隊題解以及注意事項

列隊題解以及注意事項

一道十分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了