poj 3667
题解:
想的和标算不是很一样
标算实现起来应该比较简单吧
我的做法:
对每个点维护一个值代表它能向左延伸的最大位置
然后查询时在线段树上二分nlogn
那么修改怎么进行呢
从向左延伸到的最大位置到当前位置修改为等差数列,这个操作用到的还是挺多的
将覆盖的这一段修改为0
维护区间最大值就可以了
不小心把change的条件写成了else也不知道怎么想的
本来以为这个应该慢一点,事实上差不多,可能是因为down和updata比较简单
#include <cstdio> #include <iostream> #include <cmath> #include <algorithm> #include <vector> using namespace std; #define IL inline #define rint register int #define rep(i,h,t) for (int i=h;i<=t;i++) #define dep(i,t,h) for (int i=t;i>=h;i--) char ss[1<<24],*A=ss,*B=ss; IL char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++;} template<class T>void read(T&x){ rint f=1,c;while(c=gc(),c<48||57<c)if(c=='-')f=-1;x=c^48; while(c=gc(),47<c&&c<58)x=(x<<3)+(x<<1)+(c^48);x*=f; } const int N=6e4; int ph[N*4],pt[N*4],lazy[N*4],maxa[N*4],mina[N*4],n,m; IL int max(int x,int y) { if (x>y) return(x); else return(y); } IL int min(int x,int y) { if (x<y) return(x); else return(y); } IL void updata(int x) { maxa[x]=max(maxa[x*2],maxa[x*2+1]); mina[x]=min(mina[x*2],mina[x*2+1]); } IL void down(int x) { if (!lazy[x]) return; lazy[x*2]=lazy[x*2+1]=lazy[x]; if(lazy[x]!=-1) { maxa[x*2]=lazy[x]-ph[x]; mina[x*2]=lazy[x]-pt[x]; maxa[x*2+1]=lazy[x]-ph[x*2+1]; mina[x*2+1]=lazy[x]-pt[x*2+1]; } else mina[x*2]=mina[x*2+1]=maxa[x*2]=maxa[x*2+1]=-1; lazy[x]=0; } #define mid ((h+t)/2) void build(int x,int h,int t) { ph[x]=h; pt[x]=t; if (h==t) return; build(x*2,h,mid); build(x*2+1,mid+1,t); } void change(int x,int h,int t,int h1,int t1) { if (h1<=h&&t<=t1) { lazy[x]=maxa[x]=mina[x]=-1; return; } down(x); if (h1<=mid) change(x*2,h,mid,h1,t1); if (mid<t1) change(x*2+1,mid+1,t,h1,t1); updata(x); } void change2(int x,int h,int t,int h1,int t1,int k) { if (h1<=h&&t<=t1) { lazy[x]=k; maxa[x]=k-h; mina[x]=k-t; return; } down(x); if (h1<=mid) change2(x*2,h,mid,h1,t1,k); if (mid<t1) change2(x*2+1,mid+1,t,h1,t1,k); updata(x); } int query(int x,int h,int t,int pos) { if (h==t) return(maxa[x]); down(x); if (pos<=mid) return(query(x*2,h,mid,pos)); else return(query(x*2+1,mid+1,t,pos)); } vector<int> ve; void query3(int x,int h,int t,int h1,int t1) { if(h1<=h&&t<=t1) { ve.push_back(x); return; } down(x); if (h1<=mid) query3(x*2,h,mid,h1,t1); if (mid<t1) query3(x*2+1,mid+1,t,h1,t1); } int query4(int x,int h,int t) { if (h==t) return(h); down(x); if (mina[x*2+1]==-1) return(query4(x*2+1,mid+1,t)); else return(query4(x*2,h,mid)); } int query2(int k) { if (k==0) return(1); ve.clear(); query3(1,1,n,1,k); dep(i,ve.size()-1,0) { int x=ve[i]; if (mina[x]==-1) return ((query4(x,ph[x],pt[x]))+1); } return(1); } int query1(int x,int h,int t,int pos) { if (maxa[x]<pos) return(-1); if (h==t) return(h); down(x); int ans1=query1(x*2,h,mid,pos); if (ans1!=-1) return(ans1); return(query1(x*2+1,mid+1,t,pos)); } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); read(n); read(m); build(1,1,n); change2(1,1,n,1,n,n+1); rep(i,1,m) { int x,y,z; read(x); if(x==1) { read(y); int xx=query1(1,1,n,y); if (xx==-1) { printf("0\n"); } else { printf("%d\n",xx); int yy=query2(xx-1); if (yy<=xx-1) change2(1,1,n,yy,xx-1,xx); change(1,1,n,xx,xx+y-1); } } else { read(y); read(z); z=z+y-1; int xx=query(1,1,n,z+1); if (xx==-1) xx=z; else xx+=z; xx=min(xx,n); int yy=query2(y-1); if (yy<=xx) change2(1,1,n,yy,xx,xx+1); } } return 0; }
标算:
对每个节点维护max_pre max_scc
这个也可以用平衡树来实现,这样删除节点就可以直接加一个新节点
但我觉得这应该还是挺慢的??
有空也写一下
等我写了再详细写吧。。
刚开始发现query里没有比较max_sum
应该直接掉成o(n)
然后就炸了
gdb watch真好用
#include <cstdio> #include <iostream> #include <cmath> #include <algorithm> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) char ss[1<<24],*A=ss,*B=ss; IL char gc() { return A==B&&(B=(A=ss)+fread(ss,1,1<<24,stdin),A==B)?EOF:*A++; } template<class T> void read(T &x) { rint f=1,c; while (c=gc(),c<48||57<c) if (c=='-') f=-1; x=c^48; while (c=gc(),47<c&&c<58) x=(x<<3)+(x<<1)+(c^48); x*=f; } const int N=6e4; int max_scc[N*4],max_pre[N*4],max_sum[N*4],lazy[N*4],n,m; #define mid ((h+t)/2) int maxb(int a,int b,int c) { return(max(c,max(a,b))); } IL void updata(int x,int h,int t) { max_sum[x]=maxb(max_scc[x*2]+max_pre[x*2+1],max_sum[x*2],max_sum[x*2+1]); max_pre[x]=max_pre[x*2]==(mid-h+1)?max_pre[x*2]+max_pre[x*2+1]:max_pre[x*2]; max_scc[x]=max_scc[x*2+1]==(t-mid)?max_scc[x*2+1]+max_scc[x*2]:max_scc[x*2+1]; } IL void down(int x,int h,int t) { if (!lazy[x]) return; if (lazy[x]==1) { lazy[x*2]=lazy[x*2+1]=1; max_pre[x*2]=max_scc[x*2]=max_sum[x*2]=mid-h+1; max_pre[x*2+1]=max_scc[x*2+1]=max_sum[x*2+1]=t-mid; } else { lazy[x*2]=lazy[x*2+1]=-1; max_pre[x*2]=max_scc[x*2]= max_pre[x*2+1]=max_scc[x*2+1]= max_sum[x*2]=max_sum[x*2+1]=0; } lazy[x]=0; } void build(int x,int h,int t) { max_pre[x]=max_scc[x]=max_sum[x]=t-h+1; if (h==t) return; build(x*2,h,mid); build(x*2+1,mid+1,t); } void change(int x,int h,int t,int h1,int t1,bool k) { if (h1<=h&&t<=t1) { if (k==1) lazy[x]=1,max_pre[x]=max_scc[x]=max_sum[x]=t-h+1; else lazy[x]=-1,max_pre[x]=max_scc[x]=max_sum[x]=0; return; } down(x,h,t); if (h1<=mid) change(x*2,h,mid,h1,t1,k); if (mid<t1) change(x*2+1,mid+1,t,h1,t1,k); updata(x,h,t); } int query(int x,int h,int t,int last,int k) { if (max_pre[x]+last>=k) return(h+k-last-1); if (max_sum[x]<k) return(-1); if (h==t) return(-1); down(x,h,t); int xx=query(x*2,h,mid,0,k); if (xx!=-1) return(xx); int tmp=max_scc[x*2]==(mid-h+1)?max_scc[x*2]+last:max_scc[x*2]; return(query(x*2+1,mid+1,t,tmp,k)); } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); read(n); read(m); build(1,1,n); rep(i,1,m) { int x,y,z; read(x); if (x==1) { read(y); int xx=query(1,1,n,0,y); if (xx==-1) { printf("0\n"); } else { printf("%d\n",xx-y+1); change(1,1,n,xx-y+1,xx,0); } } else { read(y); read(z); change(1,1,n,y,y+z-1,1); } } return 0; }