AT_wtf22_day1_d Welcome to Tokyo!
传送门
原问题为在长度为
也就是求一组
最多选
总结一下就是:求出一组非负整数
在
于是猜测这是一个全幺模矩阵,但是并不满足每一列至多两个元素。
考虑哪个不等式是没有必要的。
可以发现当
于是这就是一个全幺模矩阵,把
考虑转化一下原问题。
先给每个不等式两边乘个系数:
设
则:
把所有不等式相加:
若
即
于是
于是我们得到了原问题的对偶问题:
求出数组
求
由于
可以发现
也就是要选出来一个区间的集合
考虑对于每个
设
考虑增量构造,每次取
可以开一个线段树维护每个点被覆盖的次数,再开一个线段树维护区间,在线段树上二分,总复杂度
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,m,rs[N],q[N],hd,tl;
struct ndP{
int l,r;
friend bool operator<(ndP a,ndP b){
return a.r<b.r;
}
}w[N];
namespace tr{
struct node{
int l,r,laz,sm;
}p[N<<2];
void upset(int x){
p[x].sm=max(p[x<<1].sm,p[x<<1|1].sm);
}
void add(int x,int sm){
p[x].laz+=sm;
p[x].sm+=sm;
}
void reset(int x,int l,int r){
p[x].l=l,p[x].r=r;
if(l==r)return;
int mid=l+r>>1;
reset(x<<1,l,mid);
reset(x<<1|1,mid+1,r);
}
void dnset(int x){
if(p[x].laz){
add(x<<1,p[x].laz);
add(x<<1|1,p[x].laz);
p[x].laz=0;
}
}
void add(int x,int l,int r,int sm){
if(l<=p[x].l&&r>=p[x].r){
add(x,sm);
return;
}
int mid=p[x].l+p[x].r>>1;
dnset(x);
if(l<=mid)add(x<<1,l,r,sm);
if(r>mid)add(x<<1|1,l,r,sm);
upset(x);
}
int gets(int x,int l,int r){
if(l>r)return 0;
if(l==0)return 1e9;
if(l<=p[x].l&&r>=p[x].r)return p[x].sm;
dnset(x);
int mid=p[x].l+p[x].r>>1;
if(r<=mid)return gets(x<<1,l,r);
if(l>mid)return gets(x<<1|1,l,r);
return max(gets(x<<1,l,r),gets(x<<1|1,l,r));
}
}
struct node{
int l,r,sm;
}p[N<<2];
void upset(int x){
p[x].sm=max(p[x<<1].sm,p[x<<1|1].sm);
}
void reset(int x,int l,int r){
p[x].l=l,p[x].r=r;
if(l==r){
p[x].sm=w[l].l;
return;
}
int mid=l+r>>1;
reset(x<<1,l,mid);
reset(x<<1|1,mid+1,r);
upset(x);
}
void sets(int x,int d,int sm){
if(p[x].l==p[x].r){
p[x].sm=sm;
return;
}
if(d<=(p[x].l+p[x].r>>1))sets(x<<1,d,sm);
else sets(x<<1|1,d,sm);
upset(x);
}
int gets(int x,int k){
if(p[x].l==p[x].r)return p[x].l;
//cout<<x<<" "<<p[x].l<<" "<<p[x].r<<" "<<p[x<<1].sm<<" "<<k<<endl;
if(tr::gets(1,p[x<<1].sm,n)<k)return gets(x<<1,k);
return gets(x<<1|1,k);
}
inline int read(){
int res=0;char c;
do{
c=getchar();
}while(!isdigit(c));
while(isdigit(c)){
res=res*10+c-'0';
c=getchar();
}
return res;
}
void print(int x){
if(x>=10)print(x/10);
putchar(x%10+'0');
}
signed main(){
cin>>n>>m;
for(int i=1;i<=m;i++)w[i].l=read(),w[i].r=read();
sort(w+1,w+m+1);
w[m+1].l=1e9;
reset(1,1,m+1);
tr::reset(1,1,n);
for(int i=1;i<=m;i++){
rs[i]=rs[i-1];
int x=gets(1,i);
for(int j=x;j<=m;j=gets(1,i)){
rs[i]++;
sets(1,j,0);
tr::add(1,w[j].l,w[j].r,1);
// cout<<j<<" "<<w[j].l<<" "<<w[j].r<<endl;
}
// cout<<i<<" "<<rs[i]<<endl;
}
hd=1;
for(int i=0;i<=m;i++){
while(hd<tl&&1ll*(rs[q[tl]]-rs[q[tl-1]])*(i-q[tl])<=1ll*(rs[i]-rs[q[tl]])*(q[tl]-q[tl-1]))tl--;
q[++tl]=i;
}
vector<int>qs;
for(int i=n;i>=1;i--){
int res=1e9;
while(hd<tl&&1ll*i*q[hd]-rs[q[hd]]>1ll*i*q[hd+1]-rs[q[hd+1]])hd++;
res=m-rs[q[hd]]+1ll*i*q[hd];
qs.push_back(res);
}
while(qs.size())print(qs.back()),putchar('\n'),qs.pop_back();
}