BJOI2017 开车

  • 一道神题,对拍狂该了两个小时,终于过了,常数还巨大
  • 首先答案最优肯定是车和加油站都排好须一一对应,现在我们将所有的有用坐标离散化,考虑维护每一段距离对答案的贡献
  • 我们发现,如果把车设成1,加油站设成-1,放在其所在的位置上,累一遍前缀和,那么每个位置上的数值就是现在失配的车或加油站,那么贡献为其绝对值乘上那段区间的距离。
  • 我们考虑分块维护贡献,对每个块对其按前缀和排序,这样可以将绝对值去掉,改动车的位置实际上就是把原来地方减一,将新的地方加一
  • 对于边角我们暴力修改并重构该块,重新计算贡献,对于完整的块我们打上lazy标记,计算式二分零点位置计算贡献即可
#include<bits/stdc++.h>
using namespace std;
typedef int sign;
typedef long long ll;
#define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
#define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
const int N=5e4+5;
template<typename T>bool cmax(T &a,T b){return (a<b)?a=b,1:0;}
template<typename T>bool cmin(T &a,T b){return (a>b)?a=b,1:0;}
template<typename T>T read()
{
  T ans=0,f=1;
  char ch=getchar();
  while(!isdigit(ch)&&ch!='-')ch=getchar();
  if(ch=='-')f=-1,ch=getchar();
  while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
  return ans*f;
}
template<typename T>void write(T x,char y)
{
  if(x==0)
  {
      putchar('0');putchar(y);
      return;
  }
  if(x<0)
  {
      putchar('-');
      x=-x;
  }
  static char wr[20];
  int top=0;
  for(;x;x/=10)wr[++top]=x%10+'0';
  while(top)putchar(wr[top--]);
  putchar(y);
}
void file()
{
  #ifndef ONLINE_JUDGE
      freopen("4908.in","r",stdin);
      freopen("4908.out","w",stdout);
  #endif
}
int n,m;
int a[N],b[N],q[N*3],tot;
int car[N],pos[N];
void input()
{
    n=read<int>();
    For(i,1,n)a[i]=q[++tot]=read<int>();
    For(i,1,n)b[i]=q[++tot]=read<int>();
    m=read<int>();
    For(i,1,m)car[i]=read<int>(),pos[i]=q[++tot]=read<int>();
}
#define find(x) lower_bound(q+1,q+tot+1,x)-q
int ac_pos[N*3];
ll sum[N*3],dis[N*3];
int block,st[400],ed[400],lazy[400],tim,blcok;
ll val[400],num[400][400];
ll ans;
struct node
{
    ll sum,dis,id;
    bool operator < (const node &s)const
    {return sum<s.sum;}
}e[N*3];
ll w[400][400];
void rebuild(int id)
{
//  cout<<"build"<<' '<<id<<endl;
//  For(i,st[id],ed[id])cout<<e[i].sum<<' '<<e[i].dis<<endl;
//  puts("");
    ans-=val[id];val[id]=0;
    For(i,st[id],ed[id])e[i].sum+=lazy[id];
    lazy[id]=0;
    sort(e+st[id],e+ed[id]+1);
    For(i,st[id],ed[id])
    {
        ac_pos[e[i].id]=i;
        num[id][i-st[id]+1]=num[id][i-st[id]]+e[i].dis*e[i].sum;
        w[id][i-st[id]+1]=w[id][i-st[id]]+e[i].dis;
        //  cout<<e[i].sum<<' '<<e[i].dis<<endl;
        val[id]+=abs(e[i].sum)*e[i].dis;    
    }
    ans+=val[id];
    //puts("");
}
void recal(int id)
{
    //if(!lazy[id])return;
    //cout<<"id"<<' '<<id<<endl;
    //cout<<"val"<<' '<<val[id]<<endl;
    //cout<<"lazy"<<' '<<lazy[id]<<endl;
    //For(i,st[id],ed[id])cout<<e[i].sum<<' '<<e[i].dis<<endl;
    ans-=val[id];val[id]=0;
    node temp={-lazy[id],0};
    int p;
    p=lower_bound(e+st[id],e+ed[id]+1,temp)-e-st[id];
    //cout<<"p"<<' '<<p<<endl;
    //cout<<"num"<<' '<<num[id][p]<<endl;
    val[id]+=abs((num[id][p])+w[id][p]*lazy[id]);
    temp={-lazy[id]+1,0};
    p=lower_bound(e+st[id],e+ed[id]+1,temp)-e-st[id];
    //cout<<"p"<<' '<<p<<endl;
    val[id]+=abs((num[id][ed[id]-st[id]+1]-num[id][p])+lazy[id]*(w[id][ed[id]-st[id]+1]-w[id][p]));
    ans+=val[id];
    //cout<<"val"<<' '<<val[id]<<endl;
    //puts("");
}
int bl[N*3];
void init()
{
    sort(q+1,q+tot+1);
    tot=unique(q+1,q+tot+1)-q-1;
    For(i,1,n)a[i]=find(a[i]),++sum[a[i]];
    For(i,1,n)b[i]=find(b[i]),--sum[b[i]];
    /*For(i,1,n)cout<<a[i]<<' ';
    cout<<endl;
    For(i,1,n)cout<<b[i]<<' ';
    cot<<endl;*/
    For(i,1,m)pos[i]=find(pos[i]);
    For(i,1,tot)sum[i]+=sum[i-1];
    //For(i,1,tot)cout<<sum[i]<<endl;
    For(i,1,tot-1)dis[i]=q[i+1]-q[i];
    tim=sqrt(tot);
    if(tim==1)++tim;
    For(i,1,tot)
    {
        if(i%tim==1)st[++block]=i;
        if(i%tim==0||i==tot)ed[block]=i;
        bl[i]=block;
        e[i]=(node){sum[i],dis[i],i};
        //cout<<e[i].sum<<' '<<e[i].dis<<endl;
    }
    For(i,1,block)rebuild(i);
//  For(i,1,tot)cout<<e[i].sum<<' '<<e[i].dis<<endl;
//  puts("");
    //For(i,1,tot)cout<<i<<' '<<e[i].sum<<' '<<e[i].dis<<endl;
}
void update(int p,int v)
{
    For(i,bl[p],block)
    {
        if(st[i]<p)
        {
            For(j,p,ed[i])e[ac_pos[j]].sum+=v;
            rebuild(i);
        }
        else 
        {
            lazy[i]+=v;
            recal(i);
        }
    }
}
void work()
{
    write(ans,'\n');
    For(i,1,m)
    {
        update(a[car[i]],-1);
        a[car[i]]=pos[i];
        update(a[car[i]],1);
        write(ans,'\n');
    }
}
int main()
{
    file();
    input();
    init();
    work();
    return 0;
}

转载于:https://www.cnblogs.com/dengyixuan/p/8761295.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值