Try Booking
题解
树套树板子题
我们可以对于
i
∈
[
1
,
n
]
i\in[1,n]
i∈[1,n]的每个情况,都去寻找它会选取那些订单。
很明显,它选取的订单不会超过
∑
i
=
1
n
⌊
n
i
⌋
=
l
n
n
\sum_{i=1}^{n}\left\lfloor\frac{n}{i}\right\rfloor=ln\,n
∑i=1n⌊in⌋=lnn。
对于每个
i
i
i,我们可以都先找一下我对于区间
[
1
,
n
]
[1,n]
[1,n]中,会先选取哪一个订单。
选取后,当前区间会断裂成两个子区间,我们在递归下去,寻找在该子区间中我们会先选取那个订单。
很明显,对于任意一个区间,我们都会首先去找这个区间中长度不小于
i
i
i的编号最小的一个订单,也就是说,我们需要一个数据结构去对其进行维护。
对于长度不小于
i
i
i这个条件,我们可以先将其离线下来,按长度从大到小依次加入订单,再在当前所需要的区间中寻找编号最小的订单。
寻找订单的操作,我们可以通过一个线段树套线段树来维护,外层线段树维护左端点的区间,内层线段树维护右端点的的区间中编号的最小值。
很明显查操作与修改操作都是
O
(
l
o
g
2
n
)
O\left(log^2n\right)
O(log2n)的。
而我们总共会进行
n
l
n
n
nln\,n
nlnn次询问与
m
m
m次修改,所以总时间复杂度为
O
(
n
l
o
g
2
n
l
n
n
+
m
l
o
g
2
n
)
O\left(nlog^2\,nln\,n+mlog^2\,n\right)
O(nlog2nlnn+mlog2n)。
注意内层区间线段树的点数要开大点,达到
m
l
o
g
2
n
mlog^2n
mlog2n的级别,不然会TLE 毕竟RE爆什么都有可能,笔者就TLE了。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 50005
#define MAXM 100005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int zero=500;
const LL jzm=2333;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int add(int x,int y){return x+y<mo?x+y:x+y-mo;}
int n,m,root[MAXN<<2],ans[MAXN];
struct node{int l,r,id;}s[MAXM],p[MAXM];
struct ming{int lson,rson,mn;ming(){lson=rson=0;mn=1e5+1;}};
bool cmp(node x,node y){return x.r-x.l>y.r-y.l;}
class SegmentTree{
public:
int tot;ming tr[MAXM*200];
void insert(int &rt,int l,int r,int ai,int id){
if(l>r||l>ai||r<ai)return ;if(!rt)rt=++tot;int mid=l+r>>1;
tr[rt].mn=min(tr[rt].mn,id);if(l==r)return ;
if(ai<=mid)insert(tr[rt].lson,l,mid,ai,id);
if(ai>mid)insert(tr[rt].rson,mid+1,r,ai,id);
}
int query(int rt,int l,int r,int ai){
if(l>r||l>ai||!rt)return m+1;
if(r<=ai)return tr[rt].mn;int mid=l+r>>1,res=m+1;
if(ai<=mid)res=query(tr[rt].lson,l,mid,ai);
else res=min(tr[tr[rt].lson].mn,query(tr[rt].rson,mid+1,r,ai));
return res;
}
}T;
void insert(int rt,int l,int r,int ai,int pos,int id){
if(l>r||l>ai||r<ai)return ;int mid=l+r>>1;
T.insert(root[rt],1,n,pos,id);if(l==r)return ;
if(ai<=mid)insert(rt<<1,l,mid,ai,pos,id);
if(ai>mid)insert(rt<<1|1,mid+1,r,ai,pos,id);
}
int query(int rt,int l,int r,int al,int ar){
if(l>r||al>ar||l>ar||r<al)return m+1;int mid=l+r>>1,res=m+1;
if(al<=l&&r<=ar)return T.query(root[rt],1,n,ar);
if(al<=mid)res=min(query(rt<<1,l,mid,al,ar),res);
if(ar>mid)res=min(query(rt<<1|1,mid+1,r,al,ar),res);
return res;
}
void sakura(int l,int r,int lim){
if(r-l+1<lim||l>r)return ;int id=query(1,1,n,l,r);
if(id<1||id>m)return ;ans[lim]+=p[id].r-p[id].l+1;
sakura(l,p[id].l-1,lim);sakura(p[id].r+1,r,lim);
}
signed main(){
read(n);read(m);
for(int i=1;i<=m;i++)read(s[i].l),read(s[i].r),s[i].id=i,p[i]=s[i];
sort(s+1,s+m+1,cmp);int id=1;
for(int i=n;i>0;i--){
while(id<=m&&s[id].r-s[id].l+1>=i)
insert(1,1,n,s[id].l,s[id].r,s[id].id),id++;
sakura(1,n,i);
}
for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
return 0;
}