zoukankan      html  css  js  c++  java
  • 题解 [BJOI2017]开车

    题目传送门

    题目大意

    (n)个汽车和(n)个加油站,坐标分别为(a_{1,2,...,n})(b_{1,2,...,n})。每辆汽车会到一个加油站,求出最小移动距离之和。有(m)次修改,每次将某辆汽车的坐标进行修改,求出修改后的最小移动距离之和。

    (n,mle 5 imes 10^4)

    思路

    看到题解都写得比较繁杂,这里提供一种不是那么繁杂的方法。借鉴了Miracle的博客shadowice1984的题解

    首先,不难看出对于某一条边,它的贡献为它的长度乘上(|sum|),其中,(sum)就是在它之前的汽车-在它之前的加油站。它的意义就是因为要一一对应,所以差的数量就需要通过移动填补,而移动就需要经过该边。

    而我们的修改操作,相当于删掉一个点再加入一个点。考虑加入一个点,那我们就相当于把后面的点的(sum+1)。但是因为贡献里面带有绝对值,所以我们不能直接搞,对于这种问题我们一个常用的解决方法就是直接分块。对于某个块,我们可以按(sum)大小排序,二分找到分界点,然后分别考虑(sum< 0)(sumge0)的情况即可。删掉一个点同理。

    于是,我们就可以在(Theta(nsqrt n(log sqrt n)))的时间复杂度内解决这个问题。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Abs(x) ((x)>=0?(x):-(x))
    #define Int register int
    #define ll long long
    #define MAXN 200005
    #define MAXM 455
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
    template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
    template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    int n,m,un,a[MAXN],b[MAXN],tmp[MAXN];
    
    struct Query{
    	int x,y;
    }q[MAXN];
    
    ll ans;
    int siz,val[MAXN],sum[MAXN],bel[MAXN],ord[MAXN],col[MAXM],cor[MAXM],tag[MAXN],sval[MAXN];
    
    bool cmp (int a,int b){return sum[a] < sum[b];}
    
    void rebuild (int x){
    	sort (ord + col[x],ord + cor[x] + 1,cmp);
    	sval[col[x]] = val[ord[col[x]]];for (Int i = col[x] + 1;i <= cor[x];++ i) sval[i] = sval[i - 1] + val[ord[i]];
    }
    
    void init (){
    	for (Int i = 1;i <= n;++ i) sum[a[i]] ++,sum[b[i]] --;
    	for (Int i = 1;i <= un;++ i){
    		if (i < un) val[i] = tmp[i + 1] - tmp[i];
    		sum[i] += sum[i - 1],ans += 1ll * Abs (sum[i]) * val[i];
    	}
    	siz = ceil (sqrt (un));
    	for (Int i = 1;i <= un;++ i){
    		bel[i] = (i - 1) / siz + 1,ord[i] = i;
    		if (!col[bel[i]]) col[bel[i]] = i;
    		cor[bel[i]] = i;
    	}
    	for (Int i = 1;i <= bel[un];++ i) rebuild (i);
    }
    
    void ins (int x){
    	for (Int i = x;i <= cor[bel[x]];++ i){
    		ans += 1ll * val[i] * (sum[i] + tag[bel[x]] >= 0 ? 1 : -1);//注意:三目运算符优先级比加减乘除低 
    		sum[i] ++;
    	}
    	rebuild (bel[x]);
    	for (Int i = bel[x] + 1;i <= bel[un];++ i){
    		int l = col[i],r = cor[i],res = -1;
    		while (l <= r){
    			int mid = (l + r) >> 1;
    			if (sum[ord[mid]] + tag[i] >= 0) res = mid,r = mid - 1;
    			else l = mid + 1;
    		}
    		if (res == -1) ans -= sval[cor[i]];
    		else if (res == col[i]) ans += sval[cor[i]];
    		else{
    			ans -= sval[res - 1];
    			ans += sval[cor[i]] - sval[res - 1];
    		}
    		tag[i] ++;
    	}
    }
    
    void del (int x){
    	for (Int i = x;i <= cor[bel[x]];++ i){
    		ans += 1ll * val[i] * (sum[i] + tag[bel[x]] <= 0 ? 1 : -1);//注意:三目运算符优先级比加减乘除低 
    		sum[i] --;
    	}
    	rebuild (bel[x]);
    	for (Int i = bel[x] + 1;i <= bel[un];++ i){
    		int l = col[i],r = cor[i],res = -1;
    		while (l <= r){
    			int mid = (l + r) >> 1;
    			if (sum[ord[mid]] + tag[i] <= 0) res = mid,l = mid + 1;
    			else r = mid - 1;
    		}
    		if (res == -1) ans -= sval[cor[i]];
    		else if (res == cor[i]) ans += sval[cor[i]];
    		else{
    			ans += sval[res];
    			ans -= sval[cor[i]] - sval[res];
    		}
    		tag[i] --;
    	}
    }
    
    signed main(){
    	read (n);
    	for (Int i = 1;i <= n;++ i) read (a[i]),tmp[++ un] = a[i];
    	for (Int i = 1;i <= n;++ i) read (b[i]),tmp[++ un] = b[i];
    	read (m);for (Int i = 1;i <= m;++ i) read (q[i].x,q[i].y),tmp[++ un] = q[i].y;
    	sort (tmp + 1,tmp + un + 1),un = unique (tmp + 1,tmp + un + 1) - tmp - 1;
    	for (Int i = 1;i <= n;++ i) a[i] = lower_bound (tmp + 1,tmp + un + 1,a[i]) - tmp,b[i] = lower_bound (tmp + 1,tmp + un + 1,b[i]) - tmp;
    	for (Int i = 1;i <= m;++ i) q[i].y = lower_bound (tmp + 1,tmp + un + 1,q[i].y) - tmp;
    	init (),write (ans),putchar ('
    ');
    	for (Int i = 1,x,y;i <= m;++ i){
    		x = q[i].x,y = q[i].y;
    		del (a[x]),ins (a[x] = y);
    		write (ans),putchar ('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    Google 嘘! 嘘!
    zabbix fast
    zabbix
    kernel update
    列表推导
    Ddos 反射性防护 simple
    file cycle
    Scala
    Hadoop
    数据库
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13371730.html
Copyright © 2011-2022 走看看