1 solutions
-
0
本例中需要支持如下操作,在 ( ) 的方阵中,如果让 出方阵,那么
- 找到标号第 ( ) 大的行,并且在该行中找到第 ( ) 大的列,将对应的元素 取出
- 然后把该行中 整体往前挪一位
- 然后操作第 列,将第 列 整体往上挪一位
- 最后把取出来的元素插入 处
注意到我们需要对 行,以及第 列求 前缀第 (k ) 大
可以考虑一开始建 棵线段树,其中每一棵线段树初始只有一个根节点
这样第 棵线段树维护 行,第 棵线段树维护第 列
将线段树写成 动态开点,这样就可以尝试维护操作了,维护区间内被删除了多少个数
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int N=300010,M=N*21; int n,m,Q; struct Node{ int l,r,cnt; }tr[M]; int root[N],idx; vector<LL> g[N]; int query(int &u,int l,int r,int x) { if(!u) u=++idx; if(l==r) return r; int mid=l+r>>1; int left=mid-l+1-tr[tr[u].l].cnt; if(x<=left) return query(tr[u].l,l,mid,x); //当前x在左边 return query(tr[u].r,mid+1,r,x-left); //当前x在右边 } void update(int &u,int l,int r,int x) { if(l==r) tr[u].cnt++;//多了一个 else{ int mid=l+r>>1; if(x<=mid) update(tr[u].l,l,mid,x); else update(tr[u].r,mid+1,r,x); tr[u].cnt=tr[tr[u].l].cnt+tr[tr[u].r].cnt; //根据子节点计算当前节点 } } int main() { cin>>n>>m>>Q; int L=max(n,m)+Q; while(Q--) { int x,y; cin>>x>>y; if(y==m) //最后一列 { int r=query(root[n+1],1,L,x); //最后一列的线段树中找到第x个数 update(root[n+1],1,L,r); LL id=r<=n?(r-1ll)*m+m:g[n+1][r-n-1]; //计算位置 cout<<id<<endl; g[n+1].push_back(id); //删除的这个数放到最后一个位置上 } else { int c=query(root[x],1,L,y); //在x行循环第y个元素 update(root[x],1,L,c); //删除对应的元素 LL id=c<m?(x-1ll)*m+c:g[x][c-m]; //得到对应的下标 cout<<id<<endl; g[n+1].push_back(id); //删除的元素放到最后一列 int r=query(root[n+1],1,L,x); //最后一列从上往下的第x个元素 update(root[n+1],1,L,r); id=r<=n?(r-1ll)*m+m:g[n+1][r-n-1]; //得到编号 g[x].push_back(id); //放到第x个线段树之中 } } return 0; }
- 1
Information
- ID
- 1129
- Time
- 2000ms
- Memory
- 256MiB
- Difficulty
- 10
- Tags
- # Submissions
- 1
- Accepted
- 1
- Uploaded By