高质量好题:[BJOI2017]开车
质量高,题目好,空白小,写不下
比较巧妙的一点是把点对之间的贡献拆成了边的贡献,这样就等价于对每一条线段维护其左边的\(|A-B|\) 。
这个东西的维护方法有很多,但是似乎都离不开分块。
可以用序列分块套值域分块实现 \(O(n \sqrt{n})\) 的复杂度,但是本人比较蠢,写了个用 vector 实现的 \(O(n\sqrt{n} \log{\sqrt{n}})\) 的版本。
代码写屎了最好的方式不是继续调试,而是重构。
还有,记得多封装,虽然常数大了,但是正确性会高很多,卡常是在代码正确了之后再考虑的事情。
Code
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define ll long long
#define ui unsigned int
il ll read(){
bool f=true;ll x=0;
register char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=false;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
if(f) return x;
return ~(--x);
}
il void write(const ll &x){if(x>9) write(x/10);putchar(x%10+'0');}
il void print(const ll &x) {x<0?putchar('-'),write(~(x-1)):write(x);putchar('\n');}
il ll max(const ll &a,const ll &b){return a>b?a:b;}
il ll min(const ll &a,const ll &b){return a<b?a:b;}
/*
把贡献拆到每条线上
每一段的贡献就是abs(左边的a-b)
那么这个东西可以用值域分块来搞
*/
const int MAXN=3e5+7;
const int MAXM=1e5+7;
#define zero 5e4
int n,a[MAXN],b[MAXN],d[MAXN];
#define pii pair<int,ll>
#define len(x) (x.second-x.first+1)
#define B 256
struct Block
{
int tag;
ll sum;
vector<pii> vc;
ll query(int l,int r){
if(l>r) return 0;
return vc[r].second-vc[l-1].second;
}
void add(){
int pos=lower_bound(vc.begin(),vc.end(),(pii){tag,0})-vc.begin();
sum+=query(pos,vc.size()-1);
sum-=query(1,pos-1);
tag--;
}
void del(){
int pos=--upper_bound(vc.begin(),vc.end(),(pii){tag+1,-1})-vc.begin();
sum+=query(1,pos);
sum-=query(pos+1,vc.size()-1);
tag++;
}
}blo[MAXN/B+10];
set<pii> s;
vector<pii> vec;
pii q[MAXM];
int m,tot;
void rebuild(int id){
int l=max(id*B,1),r=min(id*B+B-1,tot);
if(blo[id].vc.empty()) blo[id].vc.resize(r-l+1+1);
for(ri i=l;i<=r;++i) d[i]+=zero-blo[id].tag;
blo[id].tag=zero;blo[id].sum=0;
blo[id].vc[0]=(pii){-1,0};
for(ri i=l;i<=r;++i) blo[id].vc[i-l+1]=(pii){d[i]+zero,len(vec[i])},blo[id].sum+=len(vec[i])*abs(d[i]);
sort(blo[id].vc.begin(),blo[id].vc.end());
for(ri i=1;i<blo[id].vc.size();++i) blo[id].vc[i].second+=blo[id].vc[i-1].second;
}
void add(int l,int r){
if(l>r) return;
if(l/B==r/B){
for(ri i=l;i<=r;++i) d[i]++;
rebuild(l/B);
return;
}
add(l,l/B*B+B-1);
add(r/B*B,r);
for(ri i=l/B+1;i<r/B;++i) blo[i].add();
}
void del(int l,int r){
if(l>r) return;
if(l/B==r/B){
for(ri i=l;i<=r;++i) d[i]--;
rebuild(l/B);
return;
}
del(l,l/B*B+B-1);
del(r/B*B,r);
for(ri i=l/B+1;i<r/B;++i) blo[i].del();
}
ll query(){
ll ans=0;
for(ri i=0;i<=tot/B;++i) ans+=blo[i].sum;
return ans;
}
void insert(int pos){
auto it=--s.upper_bound((pii){pos,2e9});
if(it->first==pos&&it->second==pos) return;
if(it->first<pos) s.insert((pii){it->first,pos-1});
if(it->second>pos) s.insert((pii){pos+1,it->second});
s.insert((pii){pos,pos});
s.erase(it);
}
int main(){
// freopen("rand.in","r",stdin);
// freopen("2.out","w",stdout);
n=read();
s.insert((pii){0,1e9});
for(ri i=1;i<=n;++i) a[i]=read(),insert(a[i]);
for(ri i=1;i<=n;++i) b[i]=read(),insert(b[i]);
m=read();
for(ri i=1;i<=m;++i){
q[i].first=read(),q[i].second=read();
insert(q[i].second);
}
vec.push_back((pii){-1,-1});
for(auto u:s) vec.push_back(u);
sort(vec.begin(),vec.end());
tot=vec.size()-1;
for(ri i=1;i<=n;++i){
int pos=lower_bound(vec.begin(),vec.end(),(pii){a[i]+1,a[i]+1})-vec.begin();
d[pos]++;
}
for(ri i=1;i<=n;++i){
int pos=lower_bound(vec.begin(),vec.end(),(pii){b[i]+1,b[i]+1})-vec.begin();
d[pos]--;
}
for(ri i=1;i<=tot;++i) d[i]+=d[i-1];
for(ri i=0;i<=tot/B;++i) blo[i].tag=zero,rebuild(i);
print(query());
for(ri i=1;i<=m;++i){
int posl=lower_bound(vec.begin(),vec.end(),(pii){a[q[i].first]+1,a[q[i].first]+1})-vec.begin();
a[q[i].first]=q[i].second;
int posr=lower_bound(vec.begin(),vec.end(),(pii){a[q[i].first]+1,a[q[i].first]+1})-vec.begin();
if(posl<posr) del(posl,posr-1);
if(posl>posr) add(posr,posl-1);
print(query());
}
fprintf(stderr,"%lf",1.0*clock()/CLOCKS_PER_SEC);
return 0;
}