再次领教了线段树的威力。维护一个最大值,优先选择左边的,更新操作写在了查询里面。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <algorithm> #define ll long long #define INF 2139062143 #define MAXN 105 using namespace std; const int MAX_N= 1<<19; int mxn,n,h,w; int dat[MAX_N]; void build(int k,int l,int r) { dat[k]=w; if(l==r) return; build(2*k,l,(l+r)/2); build(2*k+1,(l+r)/2+1,r); } void Init() { mxn=1; while(mxn<h) mxn*=2; memset(dat,0,sizeof(dat)); build(1,1,h); } int query(int x,int k,int l,int r) { if(l==r) { dat[k]-=x; return l; } else { int ans=0; if(dat[2*k]>=x) ans=query(x,2*k,l,(l+r)/2); else ans=query(x,2*k+1,(l+r)/2+1,r); dat[k]=max(dat[2*k],dat[2*k+1]); return ans; } } int main() { while(scanf("%d%d%d",&h,&w,&n)!=EOF) { h=min(h,n); Init(); int t; for(int i=0;i<n;++i) { scanf("%d",&t); if(dat[1]<t) printf("-1\n"); else printf("%d\n",query(t,1,1,h)); } } return 0; }
后来重写了一遍。
首先h=min(h,200000),以h为结点建立线段树,树上存某个区间内宽度的最大值。这样每次查询相当于二分寻找大于t的叶结点,优先从左寻找。找到的叶结点同时要减去t,然后更新父亲结点。不存在时返回-1。
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <vector> #include <queue> #include <set> #include <map> #include <algorithm> #define ll long long #define INF 2139062143 #define inf -2139062144 #define MOD 20071027 #define MAXN 500005 #define LEN 222222<<2 using namespace std; int h,w,n; struct Segment_tree { private: int data[LEN],sz; void pushup(int o) { data[o]=max(data[o<<1],data[o<<1|1]); } int myquery(int o,int L,int R,int v) { if(L==R) { data[o]-=v; return L; } int M=(L+R)/2; int res=-1; if(v<=data[o<<1]) res=myquery(o<<1,L,M,v); else if(v<=data[o<<1|1])res= myquery(o<<1|1,M+1,R,v); pushup(o); return res; } public: void clear() { sz=h; } void build(int o,int L,int R) { if(L==R) data[o]=w; else { int M=(L+R)/2; build(o<<1,L,M); build(o<<1|1,M+1,R); data[o]=w; } } int query(int p) { return myquery(1,1,sz,p); } }; Segment_tree tree; int main() { while(scanf("%d%d%d",&h,&w,&n)!=EOF) { int t; h=min(h,200000); tree.clear(); tree.build(1,1,h); for(int i=0; i<n; ++i) { scanf("%d",&t); printf("%d\n",tree.query(t)); } } return 0; }