【Noip2017】D2T3列队(phalanx)

突然发现其实作为整张试卷唯一的一道数据结构题,我发现想要把它做出来还是需要一些能耐的,虽然我一直都没有做出了,现在也没有,但是我把大佬的题解看懂了,这里因为我并不是很懂,代码我也不想多讲,我在他的程序上留下了一些笔记,相信大家认真看还是可以看懂的:

(有些被注释掉的代码是我写的,事实证明,写了这些东西,程序的运行都不正常,大家也可以思考一下为什么?)

代码如下:

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T&x)
{
    x = 0;char c;int sign = 1;
    do { c = getchar();if(c == '-') sign = -1; }while(c < '0' || c > '9');
    do { x = x * 10 + c - '0'; c = getchar();  }while(c <= '9' && c >= '0');
    x *= sign;
}
inline void init(string name )
{
    string in = name + ".in",out = name + ".out";
    freopen(in.c_str(),"r",stdin);
    freopen(out.c_str(),"w",stdout);
}
const int N = 3e5 + 500,M = 1e7;
int n,m,now,o[N],q,root[N],SZ,sz[M],ls[M],rs[M];long long val[M];
inline int get_sz(int l,int r)//看大小 
{
    if(now == n + 1)
    {
        if(r <= n) return r - l + 1;
        if(l <= n) return n - l + 1;
        return 0;
    }
    if(r < m) return r - l + 1;
    if(l < m) return m - l ;
    return 0;
}
long long delete_point(int&id,int x,int l,int r)//id为当前树的编号 
{
    if(!id)//当编号为0的时候 还没有分配到编号的时候 
    {
        id = ++SZ;//分配一个 
        sz[id] = get_sz(l,r);
        if(l == r)
        {
            if(now <= n) val[id] = (long long)(now - 1) * m + l;//val是什么玄学? val存储当前位置的编号 
            else val[id] = (long long)l * m;
        }
    }
    sz[id]--;//因为这个点马上我们就要把他清除掉了 
    if(l == r) return val[id];
    int mid = (l + r) >> 1;
    if((!ls[id] && x <= (mid - l + 1)) || x <= sz[ls[id]]) return delete_point(ls[id],x,l,mid);
    else
    {
        if(!ls[id]) x -= (mid - l + 1); else x -= sz[ls[id]];//减去左树的大小,还需要理解 ,因为我们要求右边的第x-sz[ls[id]],在全队中他是第x位 
        return delete_point(rs[id],x,mid + 1,r);//补充上面的注释,因为这里的原理好像和下面不太一样。 
    }

    /* 
    if(l==r) return val[id];
    int mid=(l+r)>>1;
    if((!ls(id) && x<=mid&&x>=l)||x<=sz[ls[id]]) return delete_point(ls[id],x,l,mid);
    else
    {
        return delete_point(rs[id],x,mid+1,r);
    } 
    */ 
}
void insert_point(int&id,int x,long long w,int l,int r)
{
    if(!id)
    {
        id = ++SZ;
        sz[id] = get_sz(l,r);
        if(l == r){ val[id] = w;/*return ;*/}
    }
    sz[id]++;//因为我们马上就要加入一个点了 
    if(l == r) return ;//?应该是害怕出问题加的吧! 
    int mid = (l + r) >> 1;
    if(x <= mid) insert_point(ls[id],x,w,l,mid);
    else insert_point(rs[id],x,w,mid + 1,r);
}
int main()
{
    //init("phalanx");
    int x,y;
    read(n); read(m); read(q);
    int p = max(m,n) + q ;long long z;
    for(register int i = 1;i <= q; ++ i)
    {//delete_point代表的意思是清除点,insert_point代表的是加入点 
        read(x);read(y);
        if(y == m) now = n + 1,z = delete_point(root[now],x,1,p);
        else now = x,z = delete_point(root[now],y,1,p);
        printf("%lld\n",z);
        now = n + 1;insert_point(root[n + 1],n + ( ++o[n+1] ),z,1,p); //因为我们要在对尾插入一个点,所以说我们就要就录一下这是插入的第几个点,所以有了o[]这个变量 
        if(y != m)//只要不是在最后一列清除的点 
        {
            now = n + 1;z = delete_point(root[now],x,1,p);//删除最后一列对应的点。 
            now = x;insert_point(root[x],m - 1 + ( ++o[x] ),z,1,p);//把该店加入该行本来的倒数第二位的后面 
        }
    }
    return 0;
}
//惊了,线段树居然还可以这样玩! 还是太菜了!  
#include<bits/stdc++.h>
#define N 300004
#define M 10000001
#define LL long long
using namespace std;
int now,root[N],o[N],n,m,q,cnt;
struct sd{
    int son[2],size;
    LL val;
}node[M];
int get_sz(int l,int r)
{
    if(now==n+1)
    {
        if(r<=n) return r-l+1;
        if(l<=n) return n-l+1;
        return 0;
    }
    if(r<m) return r-l+1;
    if(l<m) return m-l;
    return 0;
}
void modify(int &k,int loc,LL v,int l,int r)
{
    if(!k)
    {
        k=++cnt;
        node[k].size=get_sz(l,r);
        if(l==r){node[k].val=v;}
    }
    node[k].size++;//用update回溯也可以
    if(l==r) return ;
    int mid=(l+r)/2;
    if(loc<=mid) modify(node[k].son[0],loc,v,l,mid);
    else modify(node[k].son[1],loc,v,mid+1,r);
}
LL query(int &k,int loc,int l,int r)
{
    if(!k) 
    {
        k=++cnt;
        node[k].size=get_sz(l,r);
        if(l==r)
        {
            if(now<=n) node[k].val=(LL)(now-1)*m+l;
            else node[k].val=(LL)l*m;
        }
    }
    node[k].size--;
    int mid=(l+r)/2;
    if(l==r) return node[k].val;
    if((!node[k].son[0]&&loc<=(mid-l+1))||loc<=node[node[k].son[0]].size) return query(node[k].son[0],loc,l,mid);
    else
    {
        if(!node[k].son[0])loc-=(mid-l+1);else loc-=node[node[k].son[0]].size;
        return query(node[k].son[1],loc,mid+1,r);
    }
}
int main()
{
    int x,y;
    scanf("%d%d%d",&n,&m,&q);
    int lim=max(n,m)+q;LL z;
    for(int i=1;i<=q;++i)
    {
        scanf("%d%d",&x,&y);
        if(y==m)now=n+1,z=query(root[now],x,1,lim);//最后一列 
        else now=x,z=query(root[now],y,1,lim);printf("%lld\n",z);
        now=n+1;modify(root[now],n+(++o[now]),z,1,lim);
        if(y!=m)
        {
            now=n+1;z=query(root[now],x,1,lim);
            now=x;modify(root[now],m-1+(++o[now]),z,1,lim);
        }
    }
    return 0;
}

直到现在我才知道原来return是直接return到主函数中去!

希望以后的一天能够独立完成它,加油!!!

posted @ 2020-07-17 08:44  Mudrobot  阅读(237)  评论(0)    收藏  举报