• 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,'
    ');
    	For(i,1,m)
    	{
    		update(a[car[i]],-1);
    		a[car[i]]=pos[i];
    		update(a[car[i]],1);
    		write(ans,'
    ');
    	}
    }
    int main()
    {
    	file();
    	input();
    	init();
    	work();
    	return 0;
    }
    
  • 相关阅读:
    Sencha Touch 框架快速入门系列
    dotTrace 使用说明
    CQRS架构中同步服务的一种实现方式
    C#中循环结构的效率问题
    面向领域驱动架构的查询实现方式
    最佳 jQuery
    DWZ&MVC的探索系列——Demo演示效果
    在Windows Azure中实现和调试一个WCF服务(上)
    现代软件工程开发体验:结对编程
    结对编程是什么?
  • 原文地址:https://www.cnblogs.com/dengyixuan/p/8761295.html
Copyright © 2020-2023  润新知