P3644 [APIO2015] 巴邻旁之桥
P3644 [APIO2015] 巴邻旁之桥
题目描述
一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域
每一块区域沿着河岸都建了恰好
城市中有
由于技术上的原因,每一座桥必须刚好连接河的两岸,桥梁必须严格垂直于河流,并且桥与桥之间不能相交。
当政府建造最多
数据范围
所有数据都保证:
Solution:
问题转化:
首先我们先来处理一下路径,我们发现河的两岸这一限制并不重要,如果一个人上班不过桥,贡献直接就是
所以现在题目变为了:在一条线段上有一些点,你需要确定一个或者两个关键点使得所有点到最近的关键点的距离
首先我们发现
对于K=2:
回顾一下贡献方程:
我们现在假设
整理得:
我们发现,一个任务 (S,T) 会去到哪个关键点是由其中点
所以我们需要动态维护一个数据结构,支持在线插入或删除一个点,区间求和,求中位数。
至于答案统计:
我们对每线段树找出中位数
值得注意的是我们应该求出区间上点的个数
Code:
#include<bits/stdc++.h> #define ll long long const int N=2e5+5; const int inf=1e9+1; using namespace std; struct Segment_Tree{ int cnt,rt; struct Tree{ int ls,rs,cnt; ll sum; }t[N*32]; void insert(int &x,int l,int r,int pos,int k) { t[x=(x ? x : ++cnt)].cnt+=k;t[x].sum+=k*pos; if(l==r)return;int mid=l+r>>1; if(pos<=mid)insert(t[x].ls,l,mid,pos,k); if(mid<pos)insert(t[x].rs,mid+1,r,pos,k); } int query_mid(int x,int l,int r,int k) { if(!x||!t[x].cnt)return 0; if(l==r)return l;int mid=l+r>>1; if(t[t[x].ls].cnt<k)return query_mid(t[x].rs,mid+1,r,k-t[t[x].ls].cnt); else return query_mid(t[x].ls,l,mid,k); } ll query_sum(int x,int l,int r,int L,int R) { if(!x||!t[x].sum)return 0; if(L<=l&&r<=R)return t[x].sum; int mid=l+r>>1;ll res=0; if(L<=mid)res+=query_sum(t[x].ls,l,mid,L,R); if(mid<R)res+=query_sum(t[x].rs,mid+1,r,L,R); return res; } ll query_cnt(int x,int l,int r,int L,int R) { if(!x||!t[x].sum)return 0; if(L<=l&&r<=R)return t[x].cnt; int mid=l+r>>1;ll res=0; if(L<=mid)res+=query_cnt(t[x].ls,l,mid,L,R); if(mid<R)res+=query_cnt(t[x].rs,mid+1,r,L,R); return res; } int Mid() { int k=t[rt].cnt>>1; return query_mid(rt,1,inf,k); } ll calc() { int mid=Mid(),k=t[rt].cnt>>1;ll res=0,tmp,cnt; cnt=query_cnt(rt,1,inf,1,mid);tmp=-query_sum(rt,1,inf,1,mid)+1ll*cnt*mid; res+=tmp; cnt=query_cnt(rt,1,inf,mid+1,inf);tmp=query_sum(rt,1,inf,mid+1,inf)-1ll*cnt*mid; res+=tmp; return res; } }T1,T2; struct task{ int l,r; bool operator<(const task &t)const{ return l+r<t.l+t.r; } }q[N]; int n,k,tot; char c[2]; ll ans,tmp; void work() { for(int i=1,x,y;i<=n;i++) { cin>>c[0]>>x>>c[1]>>y; if(x>y)swap(x,y); if(c[0]==c[1])ans+=y-x; else{q[++tot]={++x,++y};} } sort(q+1,q+1+tot);ans+=tot; for(int i=1;i<=tot;i++) { int l=q[i].l,r=q[i].r; T1.insert(T1.rt,1,inf,l,1); T1.insert(T1.rt,1,inf,r,1); } tmp=T1.calc(); if(k==1){cout<<ans+tmp;return;} for(int i=tot;i>=1;i--) { int l=q[i].l,r=q[i].r; T1.insert(T1.rt,1,inf,l,-1);T2.insert(T2.rt,1,inf,l,1); T1.insert(T1.rt,1,inf,r,-1);T2.insert(T2.rt,1,inf,r,1); ll res=T1.calc()+T2.calc(); tmp=min(tmp,res); } ans+=tmp; cout<<ans; } int main() { //freopen("P3644.in","r",stdin);freopen("P3644.out","w",stdout); ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); cin>>k>>n; work(); return 0; }