P3960
[NOIP2017 提高组] 列队
树状数组的代码基本一个也看不懂。。。
使用了动态开点线段树,常数略大,但感觉是非常实用的数据结构。
大概是给每行开一个线段树,最后一列单独开一个线段树,所以一开始每行存储的信息只有
然后考虑插入删除之类的操作。
出列一个人,就是在第
当然如果出列的人就在最后一列我们特判一下直接操作即可。
因为动态开点,所以空间只与有用的点有关(即
动态开点的时候就是初始状态的时候所以可以按照队列规律直接计算(感觉自己就是卡在这个点没想出来)。
时间复杂度
代码:
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const ll N=3e5;
ll n,m,q,tot,x,y,tmp1,tmp2;
struct dsgt{
ll cnt,num,lc,rc;
#define cnt(x) tree[x].cnt
#define num(x) tree[x].num
#define lc(x) tree[x].lc
#define rc(x) tree[x].rc
}tree[N*40];
inline ll getcnt(ll i,ll l,ll r) {
if(i<=n) r=min(r,m-1);
else r=min(r,n);
return r-l+1>0?r-l+1:0;
}
inline ll getnum(ll i,ll x) {
if(i<=n) return (i-1)*m+x;
return x*m;
}
inline ll query(ll i,ll p,ll l,ll r,ll k) {
if(l==r) {
cnt(p)=0;return num(p);
}
ll mid=(l+r)>>1;
if(!lc(p)) {
lc(p)=++tot;
cnt(lc(p))=getcnt(i,l,mid);
if(l==mid) num(lc(p))=getnum(i,l);
}
if(!rc(p)) {
rc(p)=++tot;
cnt(rc(p))=getcnt(i,mid+1,r);
if(mid+1==r) num(rc(p))=getnum(i,mid+1);
}
ll res;
if(cnt(lc(p))>=k) res=query(i,lc(p),l,mid,k);
else res=query(i,rc(p),mid+1,r,k-cnt(lc(p)));
cnt(p)=cnt(lc(p))+cnt(rc(p));
return res;
}
void ins(ll i,ll p,ll l,ll r,ll x,ll y) {
if(l==r) {
cnt(p)=1;num(p)=y;return;
}
ll mid=(l+r)>>1;
if(!lc(p)) {
lc(p)=++tot;
cnt(lc(p))=getcnt(i,l,mid);
if(l==mid) num(lc(p))=getnum(i,l);
}
if(!rc(p)) {
rc(p)=++tot;
cnt(rc(p))=getcnt(i,mid+1,r);
if(mid+1==r) num(rc(p))=getnum(i,mid+1);
}
if(x<=mid) ins(i,lc(p),l,mid,x,y);
else ins(i,rc(p),mid+1,r,x,y);
cnt(p)=cnt(lc(p))+cnt(rc(p));
}
inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9') {ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
return ret*f;
}
inline void write(ll x) {
static char buf[22];static ll len=-1;
if(x>=0) {
do{buf[++len]=x%10+48;x/=10;}while(x);
}
else {
putchar('-');
do{buf[++len]=-(x%10)+48;x/=10;}while(x);
}
while(len>=0) putchar(buf[len--]);
}
inline void writeln(ll x) {
write(x);putchar('\n');
}
int main() {
n=read();m=read();q=read();tot=n+1;
for(ll i=1;i<=q;i++) {
x=read();y=read();
if(y<m) {
writeln(tmp1=query(x,x,1,N+N,y));
tmp2=query(n+1,n+1,1,N+N,x);
ins(x,x,1,N+N,N+i,tmp2);
ins(n+1,n+1,1,N+N,N+i,tmp1);
}
else {
writeln(tmp1=query(n+1,n+1,1,N+N,x));
ins(n+1,n+1,1,N+N,N+i,tmp1);
}
}
return 0;
}