标签:分时 $1 size style algorithm math font ace iostream
听说正常写法是差分约束?
我怎么看都是贪心啊,所以就用贪心写了(其实是我忘记差分约束怎么写了)
考虑把区间按右端点排序,那么对于每个区间,我们考虑选择的数尽量贴着区间右边,因为这样还可以尽量满足之后区间的要求
(显然填在左边对后面没有任何好处,填右边一定比填左边好)
然后这样搞如果直接暴力复杂度是可以卡到 $n^2$ 的,所以考虑用线段树优化一下这个贪心
线段树维护一下当前每个位置是否已经选择,然后对于每个题目限制的区间 $l,r,x$,(区间 $[l,r]$ 内要选择 $x$ 个数)
我们首先把 $x$ 先减去当前 $[l,r]$ 内已经选择的位置数量,然后现在问题就是确定位置 $p$ ,使得把当前 $[p,r]$ 内没有选择的数选择以后恰好满足限制
这个东西显然是可以二分的,然后就做完了,复杂度因为二分时要线段树查询一下所以是 $n \log ^2 max(r) $ 的,已经可以过了
但是我脑子转不过来就是要写线段树上二分
但是正常的线段树上二分是在整颗线段树 $[1,max(r)]$ 上二分,不慌,注意到此时 $(r,max(r)]$ 的所有位置都还没选
所以把原本二分要求的值加上 $max(r)-r$ 即可在整颗线段树上二分了,复杂度 $n \log max(r)$
(如果实在听不懂的话直接看代码或许比较简单?)
线段树维护区间赋值为 $1$ 时因为每个线段树节点最多被改变一次所以甚至不用打标记,直接暴力修改即可
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘) f=-1; ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘) { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e5+7; int n,m,ans; struct dat { int l,r,mi; dat (int _l=0,int _r=0,int _mi=0) { l=_l,r=_r,mi=_mi; } inline bool operator < (const dat &tmp) const { return r!=tmp.r ? r<tmp.r : l<tmp.l; } }D[N]; struct SegTree { int T[N<<2]; void change(int o,int l,int r,int ql,int qr) { if(l>qr||r<ql||T[o]==r-l+1) return; if(l==r) { T[o]=1; return; } int mid=l+r>>1; change(o<<1,l,mid,ql,qr); change(o<<1|1,mid+1,r,ql,qr); T[o]=T[o<<1]+T[o<<1|1]; } int query_sum(int o,int l,int r,int ql,int qr) { if(l>qr||r<ql) return 0; if(l>=ql&&r<=qr) return T[o]; int mid=l+r>>1; return query_sum(o<<1,l,mid,ql,qr)+query_sum(o<<1|1,mid+1,r,ql,qr); } int query_pos(int o,int l,int r,int K) { if(l==r) return l; int mid=l+r>>1,val=r-mid-T[o<<1|1]; if(K>val) return query_pos(o<<1,l,mid,K-val); return query_pos(o<<1|1,mid+1,r,K); } }T; int main() { n=read(); int a,b,c; for(int i=1;i<=n;i++) { a=read(),b=read(),c=read(); m=max(m,b); D[i]=dat(a,b,c); } sort(D+1,D+n+1); for(int i=1;i<=n;i++) { int t=T.query_sum(1,1,m,D[i].l,D[i].r); if(t>=D[i].mi) continue; ans+=D[i].mi-t; int p=T.query_pos(1,1,m, D[i].mi-t + m-D[i].r); T.change(1,1,m,p,D[i].r); } printf("%d\n",ans); return 0; }
标签:分时 $1 size style algorithm math font ace iostream
原文地址:https://www.cnblogs.com/LLTYYC/p/11719403.html