zoukankan      html  css  js  c++  java
  • [APIO2015]八邻旁之桥

    嘟嘟嘟


    这题拿到后就瞬秒(k = 1)的情况,跟这题一模一样。


    所以我最后也只拿了31分……


    正解要推出这么个性质,就是如果只有一座桥,那么所有城市和办公室的中位数就是这座桥的位置(然而我的(k = 1)做法显然没有用到这一点……)。
    怎么证明呢?
    先用式子表示一下:就是我们要找到一个(x),满足(sum_{i = 1} ^ {m} |L_i - x| + |R_i - x|)最小,即(sum _ {i = 1} ^ {2m} |a_i - x|)最小。
    假设(x)现在是中位数,那么如果我们把(x)变小或变大了一位(这里的“一位”指的是和某一个数的大小关系发生了改变),带来的代价就是(m * Delta x - (m - 1) * Delta x = Delta x),这个值显然大于0,所以移动必定会带来正的代价。那么中位数就是最优的。


    那么(k = 2)的情况怎么办呢?
    观察发现,每一个人的距离和(|L_i - R_i|)以及距离桥的距离有关。因此我们取(L_i, R_i)的中点,看中点离哪边的桥近就走哪边。
    所以我们先把所有人按各自的中点排序(即(L_i + R_i)),然后枚举两座桥的分界点,即分界点左侧的人都上一座桥,右侧的人上另一座桥。然后两边就变成了(k = 1)的情况,分别求中位数即可。
    因为要支持动态删点和加点,所以开两棵权值线段树,支持查找第(k)大和区间求和操作。
    找完中位数后计算答案的方法和上面说的那道题一样,用前缀和整体相减即可。


    然后我因为按离散化后的值的中位数排序gg了好半天。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    typedef long long ll;
    typedef double db;
    const ll INF = 1e18;
    const db eps = 1e-8;
    const int maxn = 1e5 + 5;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    int K, n;
    
    char s1[2], s2[2];
    int a[maxn], b[maxn], t[maxn << 1], cnt[2];
    ll suma[maxn], sumb[maxn];
    In void work0()
    {
      ll ans = INF, SUM = 0;
      for(int i = 1; i <= n; ++i)
        {
          scanf("%s", s1); int val1 = read();
          scanf("%s", s2); int val2 = read();
          if(s1[0] == s2[0]) SUM += abs(val1 - val2);
          else
    	    {
    	      a[++cnt[0]] = val1, b[cnt[0]] = val2;
    	      if(s1[0] == 'B') swap(a[cnt[0]], b[cnt[0]]);
    	    }
        }
      for(int i = 1; i <= cnt[0]; ++i) t[i] = a[i];
      for(int i = 1; i <= cnt[0]; ++i) t[i + cnt[0]] = b[i];
      sort(t + 1, t + (cnt[0] << 1) + 1);
      cnt[1] = unique(t + 1, t + (cnt[0] << 1) + 1) - t - 1;
      for(int i = 1; i <= cnt[0]; ++i) a[i] = lower_bound(t + 1, t + cnt[1] + 1, a[i]) - t;
      for(int i = 1; i <= cnt[0]; ++i) b[i] = lower_bound(t + 1, t + cnt[1] + 1, b[i]) - t;
      sort(a + 1, a + cnt[0] + 1), sort(b + 1, b + cnt[0] + 1);
      for(int i = 1; i <= cnt[0]; ++i) suma[i] = suma[i - 1] + t[a[i]];
      for(int i = 1; i <= cnt[0]; ++i) sumb[i] = sumb[i - 1] + t[b[i]];
      suma[cnt[0] + 1] = suma[cnt[0]];
      sumb[cnt[0] + 1] = sumb[cnt[0]];
      for(int i = 1, pos; i <= cnt[1]; ++i)
        {
          ll sum = 0;
          pos = lower_bound(a + 1, a + cnt[0] + 1, i) - a;
          if(pos > 0) sum = 1LL * t[i] * (pos - 1) - suma[pos - 1] + suma[cnt[0]] - suma[pos - 1] - 1LL * t[i] * (cnt[0] - pos + 1);
          pos = lower_bound(b + 1, b + cnt[0] + 1, i) - b;
          if(pos > 0) sum += 1LL * t[i] * (pos - 1) - sumb[pos - 1] + sumb[cnt[0]] - sumb[pos - 1] - 1LL * t[i] * (cnt[0] - pos + 1);
          ans = min(ans, sum);
        }
      if(ans == INF) ans = 0;
      write(ans + SUM + cnt[0]), enter;
    }
    
    struct Node
    {
      int L, R;
      In bool operator < (const Node& oth)const
      {
        return L + R < oth.L + oth.R;
      }
    }q[maxn];
    int qcnt = 0, tot = 0;
    
    struct Tree
    {
      int l[maxn << 3], r[maxn << 3], siz[maxn << 3];
      ll sum[maxn << 3];
      In void build(int L, int R, int now)
      {
        l[now] = L, r[now] = R;
        sum[now] = siz[now] = 0; 
        if(L == R) return;
        int mid = (L + R) >> 1;
        build(L, mid, now << 1);
        build(mid + 1, R, now << 1 | 1);
      }
      In void pushup(int now)
      {
        sum[now] = sum[now << 1] + sum[now << 1 | 1];
        siz[now] = siz[now << 1] + siz[now << 1 | 1];
      }
      In void update(int id, int now, int flg)
      {
        if(l[now] == r[now])
          {
    	    sum[now] += 1LL * t[id] * flg;
    	    siz[now] += flg; return;
          }
        int mid = (l[now] + r[now]) >> 1;
        if(id <= mid) update(id, now << 1, flg);
        else update(id, now << 1 | 1, flg);
        pushup(now);
      }
      In ll kth(int k, int now)
      {
        if(l[now] == r[now]) return t[l[now]] * k;
        if(siz[now << 1] >= k) return kth(k, now << 1);
        else return siz[now << 1] + kth(k - siz[now << 1], now << 1 | 1);
      }
      In ll query_low(int k, int now, db d)
      {
        if(l[now] == r[now]) return d * k - 1LL * t[l[now]] * k;
        if(siz[now << 1] > k) return query_low(k, now << 1, d);
        else if(siz[now << 1] == k) return d * siz[now << 1] - sum[now << 1];
        else return d * siz[now << 1] - sum[now << 1] + query_low(k - siz[now << 1], now << 1 | 1, d);
      }
      In ll query_upp(int k, int now, db d)
      {
        if(l[now] == r[now]) return 1LL * t[l[now]] * k - d * k;
        if(siz[now << 1 | 1] > k) return query_upp(k, now << 1 | 1, d);
        else if(siz[now << 1 | 1] == k) return sum[now << 1 | 1] - d * siz[now << 1 | 1];
        else return sum[now << 1 | 1] - d * siz[now << 1 | 1] + query_upp(k - siz[now << 1 | 1], now << 1, d);
      }
      In ll Query(int len)
      {
        if(!len) return 0;
        ll mid = kth(len >> 1, 1);
        return query_low(len >> 1, 1, mid) + query_upp(len >> 1, 1, mid);
      }
    }t1, t2;
    
    In void work1()
    {
      ll ans = INF, SUM = 0;
      for(int i = 1; i <= n; ++i)
        {
          scanf("%s", s1); int val1 = read();
          scanf("%s", s2); int val2 = read();
          if(s1[0] == s2[0]) SUM += abs(val1 - val2);
          else q[++qcnt] = (Node){val1, val2}, t[++tot] = val1, t[++tot] = val2;
        }
      if(!qcnt) {write(SUM), enter; return;}
      sort(t + 1, t + tot + 1);
      tot = unique(t + 1, t + tot + 1) - t - 1;
      t1.build(1, tot, 1), t2.build(1, tot, 1);
      sort(q + 1, q + qcnt + 1);
      for(int i = 1; i <= qcnt; ++i)
        {
          q[i].L = lower_bound(t + 1, t + tot + 1, q[i].L) - t;
          q[i].R = lower_bound(t + 1, t + tot + 1, q[i].R) - t;
          t2.update(q[i].L, 1, 1), t2.update(q[i].R, 1, 1);
        }
      for(int i = 1; i <= qcnt + 1; ++i)
        {
          ll sum = t1.Query((i - 1) << 1) + t2.Query((qcnt - i + 1) << 1);
          ans = min(ans, sum);
          if(i > qcnt) break;
    	  t1.update(q[i].L, 1, 1), t1.update(q[i].R, 1, 1);
    	  t2.update(q[i].L, 1, -1), t2.update(q[i].R, 1, -1);
    	}
      write(ans + SUM + qcnt), enter;
    }
    
    int main()
    {
      K = read(), n = read();
      if(K == 1) {work0(); return 0;}
      if(K == 2) {work1(); return 0;}
      return 0;
    }
    
  • 相关阅读:
    替代传统C/S和B/S技术的下一代客户/服务器编程技术
    理想的编程语言
    nginx进程模型
    Sybase 7.0 中文乱码问题
    netfilter 链接跟踪机制与NAT原理
    TraTraffic Server 进程模型
    nginx并发模型与traffic_server并发模型简单比较
    vs/nat原理分析
    ORACLE 查询表信息
    in 跟exists的区别
  • 原文地址:https://www.cnblogs.com/mrclr/p/10562820.html
Copyright © 2011-2022 走看看