【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到主函数中去!
希望以后的一天能够独立完成它,加油!!!

浙公网安备 33010602011771号