- 首页 > it技术 > >
「NOIP2017」列队
放loj的题面好啦
题意
【「NOIP2017」列队 //线段树】有一个n行m列的方阵,第i行j列的点编号为(i-1)m+j。
给出q次操作,每次把第x行y列的点拿出来,然后把这一行它之后的点都向左推,把最后一列x行之后的点都向上推,然后把之前(x,y)的点放到最后一个位置,询问这个点的编号。
题解
//树状数组的做法我不会呀 写一写暴力一些的做法吧
维护每一行和最后一列,于是需要实现的操作就变成了找到并删掉第k个数、把一个数插到末尾。
这东西是不是随便套个数据结构就好啦?
我写了个动态开点的线段树不会别的 空间上来看是比较劣…不过512M就可以乱开了
初始状态怎么办呢…打一个等差数列的标记就好了
代码
#include
#define V 15000000
#define N 300005
#define New(w) (w=(w?w:++cnt))
using namespace std;
typedef long long ll;
char ch;
inline void rd(int &x)
{
x=0;
do ch=getchar();
while(ch<'0'||ch>'9');
do x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
while(ch>='0'&&ch<='9');
}
bool flag;
int n,m,q,Rt,cnt,L,x,y,
sz[V],c[V][2],rt[N],mx[V];
ll st[V],ans,tp;
inline void pd(int x,int l,int r,int mid)
{
if(!st[x])return;
sz[New(c[x][0])]=mx[c[x][0]]=mid-l+1;
st[c[x][0]]=st[x];
sz[New(c[x][1])]=mx[c[x][1]]=r-mid+1;
st[c[x][1]]=st[x]+(ll)(mid-l+1)*(flag?m:1);
st[x]=0;
}
void build(int &x,int l,int r,int r_,ll fr)
{
sz[New(x)]=r_-l+1,mx[x]=r_-l+1;
if(r==r_)
{st[x]=fr;
return;
}
int mid=l+r>>1;
if(r_>mid)build(c[x][1],mid+1,r,r_,fr+(ll)(mid-l+1)*(flag?m:1));
build(c[x][0],l,mid,r_>1,sz[New(x)]++,mx[x]++;
pd(x,l,r,mid);
if(mx[c[x][0]]>1;
pd(x,l,r,mid);
return (loc>sz[c[x][0]])?qry(c[x][1],mid+1,r,
loc-sz[c[x][0]]):qry(c[x][0],l,mid,loc);
}
int main()
{
rd(n),rd(m),rd(q);
L=max(n,m)+q;
for(int i=1;
i<=n;
i++)
build(rt[i],1,L,m-1,(ll)(i-1)*m+1);
flag=1,build(Rt,1,L,n,m);
while(q--)
{
rd(x),rd(y);
if(y^m)
flag=0,printf("%lld\n",ans=qry(rt[x],1,L,y)),
flag=1,tp=qry(Rt,1,L,x),
ins(Rt,1,L,ans),
flag=0,ins(rt[x],1,L,tp);
else
flag=1,printf("%lld\n",ans=qry(Rt,1,L,x)),
ins(Rt,1,L,ans);
}
}
推荐阅读