蒟蒻表示树套树是什么,能吃吗?
唉无奈本蒟蒻过于沙茶不会树套树。
只好整体二分水一水了。
跑了近4000MS,怀疑比树套树还慢了。。。。。。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=50000+5; const int inf=1e9; struct Query{ int a,b,c,cur,tp,id; }q[N],q1[N],q2[N]; int tmp[N],ans[N]; struct Node{ int l,r,sum,add; }; struct Segement_tree{ Node tr[N*4]; void pushup(int o){ tr[o].sum=tr[o<<1].sum+tr[o<<1|1].sum; } void pushdown(int o){ if(tr[o].add){ tr[o<<1].add+=tr[o].add;tr[o<<1|1].add+=tr[o].add; int len=tr[o].r-tr[o].l+1; tr[o<<1].sum+=(len-(len>>1))*tr[o].add; tr[o<<1|1].sum+=(len>>1)*tr[o].add; tr[o].add=0; } } void build(int o,int l,int r){ tr[o].l=l;tr[o].r=r; if(l==r)return; else{ int m=l+r>>1; build(o<<1,l,m);build(o<<1|1,m+1,r); } } void update(int o,int a,int b,int val){ int l=tr[o].l,r=tr[o].r; if(l==a&&b==r){ tr[o].sum+=(r-l+1)*val; tr[o].add+=val; }else{ pushdown(o); int m=l+r>>1; if(b<=m)update(o<<1,a,b,val); else if(m<a)update(o<<1|1,a,b,val); else{update(o<<1,a,m,val);update(o<<1|1,m+1,b,val);} pushup(o); } } int query(int o,int a,int b){ int l=tr[o].l,r=tr[o].r; if(l==a&&b==r)return tr[o].sum; else{ pushdown(o); int m=l+r>>1; if(b<=m)return query(o<<1,a,b); else if(m<a)return query(o<<1|1,a,b); else return query(o<<1,a,m)+query(o<<1|1,m+1,b); } } }solver; void divide(int head,int tail,int l,int r){ if(head>tail)return ; if(l==r){ for(int i=head;i<=tail;i++) if(q[i].tp==2)ans[q[i].id]=l; return; } int mid=l+r>>1; for(int i=head;i<=tail;i++) if(q[i].tp==1&&q[i].c>mid)solver.update(1,q[i].a,q[i].b,1); else if(q[i].tp==2)tmp[i]=solver.query(1,q[i].a,q[i].b); for(int i=head;i<=tail;i++) if(q[i].tp==1&&q[i].c>mid)solver.update(1,q[i].a,q[i].b,-1); int l1=0,l2=0; for(int i=head;i<=tail;i++) if(q[i].tp==2){ if(q[i].cur+tmp[i]>=q[i].c)q1[++l1]=q[i]; else q[i].cur+=tmp[i],q2[++l2]=q[i]; }else{ if(q[i].c>mid)q1[++l1]=q[i]; else q2[++l2]=q[i]; } for(int i=1;i<=l1;i++)q[head+i-1]=q1[i]; for(int i=1;i<=l2;i++)q[head+l1+i-1]=q2[i]; divide(head,head+l1-1,mid+1,r); divide(head+l1,tail,l,mid); } int main(){ int n,m;scanf("%d%d",&n,&m); int mx=-inf,mi=inf; solver.build(1,1,n); int num=0; for(int i=1;i<=m;i++){ scanf("%d%d%d%d",&q[i].tp,&q[i].a,&q[i].b,&q[i].c); if(q[i].tp==2)q[i].id=++num; else mx=max(mx,q[i].c),mi=min(mi,q[i].c); } divide(1,m,mi,mx); for(int i=1;i<=num;i++) printf("%d\n",ans[i]); return 0; }
好了现在本蒟蒻会树套树了,于是用树套树来水一水。
权值线段树套普通线段树。
于是乎~15秒多!!!!
整体二分才4秒左右好不好啊。
原来整体二分才是正解- -
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int root[200005]; int ls[20000005],rs[20000005],sum[20000005],add[20000005]; int sz,n; void pushdown(int o,int l,int r){ if(!add[o]||l==r)return; if(!ls[o])ls[o]=++sz; if(!rs[o])rs[o]=++sz; add[ls[o]]+=add[o];add[rs[o]]+=add[o]; int m=l+r>>1; sum[ls[o]]+=add[o]*(m-l+1); sum[rs[o]]+=add[o]*(r-m); add[o]=0; } void pushup(int o){ sum[o]=sum[ls[o]]+sum[rs[o]]; } void update(int &o,int l,int r,int a,int b){ if(!o)o=++sz; pushdown(o,l,r); if(l==a&&b==r){ sum[o]+=r-l+1; add[o]++; }else{ int m=l+r>>1; if(b<=m)update(ls[o],l,m,a,b); else if(m<a)update(rs[o],m+1,r,a,b); else update(ls[o],l,m,a,m),update(rs[o],m+1,r,m+1,b); pushup(o); } } int query(int o,int l,int r,int a,int b){ if(!o)return 0; pushdown(o,l,r); if(l==a&&b==r)return sum[o]; else{ int m=l+r>>1; if(b<=m)return query(ls[o],l,m,a,b); else if(m<a)return query(rs[o],m+1,r,a,b); else return query(ls[o],l,m,a,m)+query(rs[o],m+1,r,m+1,b); } } void insert(int a,int b,int c){ int o=1,l=1,r=n; while(l!=r){ int m=l+r>>1; update(root[o],1,n,a,b); if(c<=m)r=m,o=o<<1; else l=m+1,o=o<<1|1; } update(root[o],1,n,a,b); } int kth(int a,int b,int c){ int l=1,r=n,o=1; while(l!=r){ int m=l+r>>1; int tmp=query(root[o<<1|1],1,n,a,b); if(tmp>=c)l=m+1,o=o<<1|1; else r=m,o=o<<1,c-=tmp; } return l; } int main(){ int m; scanf("%d%d",&n,&m); int opt,a,b,c; while(m--){ scanf("%d%d%d%d",&opt,&a,&b,&c); if(opt==1)insert(a,b,c); else printf("%d\n",kth(a,b,c)); } return 0; }