洛谷 3960 列队——线段树
题目:https://www.luogu.org/problemnew/show/P3960
用了朴素的方法调了众多细节之后以一个很慢的速度A了……
大意是给每行开一个线段树,存1~m-1的点,最后一列开一个线段树。一开始有n*m个点开不下,但是顺序的,所以打一个标记表示它是顺序的,就不用建出它的孩子了。这样初始开了大约nlogn个节点。
线段树节点上记录 sm[ ] 表示该段内有多少个值。查询 y 位置就是查询第 x 行的线段树里第 y 靠前的值。
新加一个值就直接加到后面,不要把前面的都挪一下什么的。这样空间有点紧张。不过一次询问最多增加 2*log( max(n,m) + q ) 个点。512MB可以开3e5*80个线段树节点。
注意开long long!!!!!不仅是定义里和函数参数里,主函数里还有一处!!!
先放一下对拍程序:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=5005; int n,m,q,a[N][N],tot; int rdn() { int ret=0;char ch=getchar(); while(ch>'9'||ch<'0') ch=getchar(); while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return ret; } int main() { n=rdn(); m=rdn(); q=rdn(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=++tot; for(int i=1,d,x,y;i<=q;i++) { x=rdn(); y=rdn(); d=a[x][y]; printf("%d\n",d); for(int j=y;j<m;j++) a[x][j]=a[x][j+1]; for(int j=x;j<n;j++) a[j][m]=a[j+1][m]; a[n][m]=d; } return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<ctime> using namespace std; const int mod=300001; int n,m,q,x,y; int main() { srand(time(0)); n=rand()%mod+1; m=rand()%mod+1; q=rand()%mod+1; // n=mod-1; m=mod-1; q=mod-1; printf("%d %d %d\n",n,m,q); while(q--) { x=rand()%n+1; y=rand()%m+1; printf("%d %d\n",x,y); } return 0; }
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int main() { int cnt=0; while(1) { system(" lg3960-maker.exe > lg3960-data.in "); system(" lg3960.exe < lg3960-data.in > lg3960-zj.out "); system(" lg3960-baoli.exe < lg3960-data.in > lg3960-bl.out "); if(system(" fc lg3960-zj.out lg3960-bl.out ")) return 0; cnt++; printf("%d\n",cnt); } }
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ls Ls[cr] #define rs Rs[cr] #define ll long long using namespace std; const int N=3e5+5,M=N*80; int n,m,q,lm,rt[N],Ls[M],Rs[M],sm[M],dr[N],cr,tot; ll val[M]; bool tg[M]; struct Node{ll val;int pos;Node(ll v,int p):val(v),pos(p) {}}; int rdn() { int ret=0;char ch=getchar(); while(ch>'9'||ch<'0') ch=getchar(); while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar(); return ret; } void pshp(int cr) { tg[cr]=(tg[ls]&tg[rs]); sm[cr]=sm[ls]+sm[rs]; } void build(int &cr,int l,int r,int L,int R,ll ini) { if(L>R) return;//仅一列 cr=++tot; if(l>=L&&r<=R){sm[cr]=r-l+1; tg[cr]=1; val[cr]=ini; return;} int mid=l+r>>1; if(L<=mid) build(ls,l,mid,L,R,ini); if(mid<R) build(rs,mid+1,r,L,R,ini+(mid-l+1)); pshp(cr); } void insert(int &cr,int l,int r,int p,ll v) { if(!cr) cr=++tot; sm[cr]++; tg[cr]=0; // printf("insert l=%d r=%d sm=%d\n",l,r,sm[cr]); if(l==r) {val[cr]=v; return;} int mid=l+r>>1; if(p<=mid) insert(ls,l,mid,p,v); else insert(rs,mid+1,r,p,v); } Node query(int cr,int l,int r,int k) { // printf("l=%d r=%d k=%d sm=%d tg=%d\n",l,r,k,sm[cr],tg[cr]); if(l==r) return Node(val[cr],l); if(tg[cr]){return Node(val[cr]+k-1,l+k-1);} int mid=l+r>>1; if(k<=sm[ls]) return query(ls,l,mid,k); else return query(rs,mid+1,r,k-sm[ls]); } void del(int &cr,int l,int r,int p) { sm[cr]--; if(l==r) return; int mid=l+r>>1; if(tg[cr]) { tg[cr]=0; if(p<=mid) { rs=++tot; sm[rs]=r-mid; val[rs]=val[cr]+(mid-l+1); tg[rs]=1; ls=++tot; sm[ls]=mid-l+1; val[ls]=val[cr]; tg[ls]=1; del(ls,l,mid,p); } else { ls=++tot; sm[ls]=mid-l+1; val[ls]=val[cr]; tg[ls]=1; rs=++tot; sm[rs]=r-mid; val[rs]=val[cr]+(mid-l+1); tg[rs]=1; del(rs,mid+1,r,p); } return; } if(p<=mid) del(ls,l,mid,p); else del(rs,mid+1,r,p); } int main() { n=rdn();m=rdn();q=rdn(); lm=max(n,m)+q; for(int i=1;i<=n;i++) build(rt[i],1,lm,1,m-1,(ll)(i-1)*m+1),dr[i]=m-1; for(ll i=m,j=1;j<=n;j++,i+=m)//ll ++dr[0],insert(rt[0],1,lm,dr[0],i); for(int i=1,x,y;i<=q;i++) { x=rdn(); y=rdn(); if(y!=m) { Node d=query(rt[x],1,lm,y); printf("%lld\n",d.val); ll tmp=d.val; del(rt[x],1,lm,d.pos); d=query(rt[0],1,lm,x); ++dr[x];insert(rt[x],1,lm,dr[x],d.val); del(rt[0],1,lm,d.pos); ++dr[0];insert(rt[0],1,lm,dr[0],tmp); } else { Node d=query(rt[0],1,lm,x); printf("%lld\n",d.val); del(rt[0],1,lm,d.pos); ++dr[0];insert(rt[0],1,lm,dr[0],d.val); } } return 0; }