Loading

【题解】CF1523G Try Booking

比较清新的数据结构体。

首先观察到 \(n\) 比较小,考虑多个 $\log $ 或 根号算法。

先考虑固定 \(x\) 怎么做,我们可以写一个 calc(l,r) 函数表示时间区间在 \([l,r]\) 内的代价是多少,每次求出区间 \([l,r]\) 中编号最小的日程安排 \((x,y)\),加上它的贡献,然后递归计算 calc(l,x-1)calc(y+1,r)

手算一下发现当 \(x\) 递减时,相当于动态加入新的区间。

相当于我们只需要支持插入区间,在线查询 \(l\le (x,y) \le r\) 中编号最小的日程安排 \((x,y)\) 。这是个二维问题,直接树状数组套动态开点线段树维护,插入和查询的时间复杂度都是 \(\mathcal{O}(\log ^2 n)\)

然后对于每个 \(x\) ,调用 calc(1,n) 函数计算答案即可。

以下是时间复杂度分析。

已知 \(x\) ,则 calc(l,r) 向下递归的区间至少减少 \(x\) ,我们将每次调用的 calc(l,r) 挂在这次调用加入贡献的日程安排上,发现调用次数是 \(\mathcal{O}(\dfrac{n}{x})\) 级别的。

所以总的时间复杂度是 \(\mathcal{O}(n\log^2 n\ln n+m\log^2 n)\)\(300ms\) 稳过。这样我们就解决了这道 3200 的 DS 题。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
#define N 100005
#define inf 0x3f3f3f3f
using namespace std;
int n,m,ll[N],rr[N],rt[N],tot,p[N],ans[N];
struct node{
	int l,r,mn;
}a[N*200];
#define ls a[x].l
#define rs a[x].r
#define S a[x].mn
void ins(int &x,int l,int r,int pos,int val){
	if(!x)x=++tot,S=val;
	else S=min(S,val);
	if(l==r)return;
	int mid=(l+r)>>1;
	if(mid>=pos)ins(ls,l,mid,pos,val);
	else ins(rs,mid+1,r,pos,val);
}
int ask(int x,int l,int r,int L,int R){
	if(!x)return inf;
	if(L>=l&&R<=r)return S;
	int mid=(L+R)>>1,cur=inf;
	if(mid>=l)cur=min(cur,ask(ls,l,r,L,mid));
	if(mid<r)cur=min(cur,ask(rs,l,r,mid+1,R));
	return cur;
}
inline void add(int l,int r,int val){for(;r<=n;r+=r&-r)ins(rt[r],1,n,l,val);}
void dfs(int x,int l,int r){
	if(!x)return;
	int mid=(l+r)>>1;
	dfs(ls,l,mid);dfs(rs,mid+1,r);
}
inline int qry(int l,int r){
	int cur=inf;
	for(;r>=l;r-=r&-r)
		cur=min(cur,ask(rt[r],l,n,1,n));
	return cur;
}
int solve(int l,int r){
	if(l>r)return 0;
	int cur=qry(l,r);
	if(cur==inf)return 0;
	return rr[cur]-ll[cur]+1+solve(l,ll[cur]-1)+solve(rr[cur]+1,r);
}
bool cmp(int x,int y){return rr[x]-ll[x]>rr[y]-ll[y];}
int main(){
	scanf("%d%d",&n,&m);
	rep(i,1,m)scanf("%d%d",&ll[i],&rr[i]),p[i]=i;
	sort(p+1,p+m+1,cmp);int j=1;puts("No Copy");
	pre(i,n,1){
		while(j<=m&&rr[p[j]]-ll[p[j]]+1==i)add(ll[p[j]],rr[p[j]],p[j]),j++;
		ans[i]=solve(1,n);
	}
	rep(i,1,n)printf("%d\n",ans[i]);
	return 0;
}
posted @ 2021-10-04 17:08  7KByte  阅读(33)  评论(0编辑  收藏  举报