Uoj 285 数据分块鸡
Uoj 285 数据分块鸡
决策单调性+二维数点。
/*
{
######################
# Author #
# Gary #
# 2021 #
######################
*/
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
inline int read(){
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9'){
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x;
}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=50000+233;
int n,q;
mp seg[100000+123];
int dp[MAXN];
const int N=1<<16;
struct node{
LL val;
int cnt;
int lc,rc;
node(){val=cnt=0;}
};
inline pair<LL,int> operator + (pair<LL,int> A,pair<LL,int > B){return II(A.FIR+B.FIR,A.SEC+B.SEC);}
struct SEGMENTTREE{
node tree[N+N+17*100000+233];
int root[N];
int cnt;
void upd(int now){
tree[now].val=tree[tree[now].lc].val+tree[tree[now].rc].val;
tree[now].cnt=tree[tree[now].lc].cnt+tree[tree[now].rc].cnt;
}
SEGMENTTREE(){
root[0]=1;
cnt=N+N-1;
rb(i,1,N){
tree[i+N-1].lc=tree[i+N-1].rc=0;
tree[i+N-1].val=0;
}
rl(i,N-1,1){
tree[i].lc=i<<1;
tree[i].rc=i<<1|1;
tree[i].val=0;
}
}
pair<LL,int> query_cnt(int a,int b,int now,int l=1,int r=N+1){
if(r<=a||l>=b){
return II(0,0);
}
if(r<=b&&l>=a){
return II(tree[now].val,tree[now].cnt);
}
int mid=(l+r)>>1;
if(mid<=a) return query_cnt(a,b,tree[now].rc,mid,r);
else if(mid>=b) return query_cnt(a,b,tree[now].lc,l,mid);
return query_cnt(a,b,tree[now].lc,l,mid)+query_cnt(a,b,tree[now].rc,mid,r);
}
void modify(int pos,int val,int& now,int l=1,int r=N+1){
if(l==r-1){
tree[++cnt]=tree[now];
tree[cnt].val+=val;
tree[cnt].cnt++;
now=cnt;
return ;
}
int mid=(l+r)>>1;
int Now=++cnt;
tree[Now]=tree[now];
if(mid>pos)
modify(pos,val,tree[Now].lc,l,mid);
if(mid<=pos)
modify(pos,val,tree[Now].rc,mid,r);
upd(Now);
now=Now;
}
}sgtll,sgtrl,sgtrg;
LL query(int l,int r){
int mid=(l+r-1)>>1;
LL ret=sgtll.query_cnt(r,n+1,sgtll.root[l]).SEC;
pair<LL,int> z=sgtrl.query_cnt(l,r+1,sgtrl.root[r]);
ret+=1ll*(r-l+1)*z.SEC;
ret-=z.FIR;
z=sgtll.query_cnt(l,min(r,mid+1),sgtll.root[l-1]);
ret+=z.FIR;
ret-=1ll*(l-1)*z.SEC;
z=sgtll.query_cnt(mid+1,r,sgtll.root[l-1]);
ret-=z.FIR;
ret+=1ll*(r)*z.SEC;
mid=(l+r+2)>>1;
z=sgtrg.query_cnt(max(l+1,mid),r+1,sgtrg.root[r+1]);
ret-=z.FIR;
ret+=1ll*(r+1)*z.SEC;
z=sgtrg.query_cnt(l+1,mid,sgtrg.root[r+1]);
ret+=z.FIR;
ret-=1ll*l*z.SEC;
return ret;
}
bool cmp(mp A,mp B){
return A.SEC<B.SEC;
}
pair<int,mp> v[MAXN*2];
int main(){
scanf("%d%d",&n,&q);
--n;
rb(i,1,q){
seg[i].first=read();
seg[i].SEC=read();
seg[i].SEC--;
}
sort(seg+1,seg+1+q);
int now=1;
rb(i,1,n){
sgtll.root[i]=sgtll.root[i-1];
while(now!=q+1&&seg[now].FIR==i){
sgtll.modify(seg[now].SEC,seg[now].SEC,sgtll.root[i]);
++now;
}
}
sort(seg+1,seg+1+q,cmp);
now=1;
rb(i,1,n){
sgtrl.root[i]=sgtrl.root[i-1];
while(now!=q+1&&seg[now].SEC==i){
sgtrl.modify(seg[now].FIR,seg[now].SEC-seg[now].FIR+1,sgtrl.root[i]);
++now;
}
}
reverse(seg+1,seg+1+q);
now=1;
sgtrg.root[n+1]=1;
rl(i,n,1){
sgtrg.root[i]=sgtrg.root[i+1];
while(now!=q+1&&seg[now].SEC==i){
sgtrg.modify(seg[now].FIR,seg[now].FIR,sgtrg.root[i]);
++now;
}
}
int head=0,tail=-1;
v[++tail]=(II(0,II(1,n)));
rb(i,1,n){
pair<int,mp> now=v[head++];
dp[i]=dp[now.first]+query(now.FIR+1,i);
if(n==i) break;
now.second.FIR++;
if(now.SEC.FIR>now.SEC.SEC);
else v[--head]=now;
int to=n+1;
while(head<=tail){
int j=tail;
if(dp[v[j].FIR]+query(v[j].FIR+1,v[j].SEC.FIR) >= dp[i]+query(i+1,v[j].SEC.FIR) ){
to=v[j].SEC.FIR;
tail--;
}
else break;
}
if(head<=tail){
int j=tail;
int l=v[j].SEC.FIR+1,r=v[j].SEC.SEC;
if(dp[v[j].FIR]+query(v[j].FIR+1,r) >= dp[i] + query(i+1,r) ){
while(l<r){
int mid=(l+r)>>1;
if(dp[v[j].FIR]+query(v[j].FIR+1,mid) >= dp[i] + query(i+1,mid)) r=mid;
else l=mid+1;
}
to=l;
pair<int,mp> ba=v[j];
ba.second.SEC=to-1;
v[tail]=ba;
}
}
if(to!=n+1)
v[++tail]=(II(i,II(to,n)));
}
cout<<dp[n]<<endl;
return 0;
}