首页 > 其他分享 >At_pakencamp_2023_day1_p sol

At_pakencamp_2023_day1_p sol

时间:2024-10-04 22:44:42浏览次数:8  
标签:index return int pos sol mkp inf pakencamp day1

题面

给你两个序列\(A, B\), \(\forall u, v(u \not = v)\)之间边的权值为\(a_ua_v+b_ub_v\)。求最小生成树的边权和。

原题目

editorial

朴素的想法

考虑类似题目的做法,考虑每一次寻找最小的然后加入。发现这种思想和Boruvka比较相似。于是我们考虑Boruvka的方式来做。

对现有的连通块的基础上考虑:我们可以将这条新的边放在连通块编号在当前连通块前面的,也可以放在连通块编号在当前编号后面的(假设对当前的连通块标编号)。那么我们需要对这两部分分开计算。那么就可以转化问题了。

转化问题

问题变成了这样:

我们要维护一个数据结构,支持每次向集合\(S\)加入一个数对\((a, b)\), 并询问时给出\((x, y)\), 求\(\min \limits_{(a, b) \in S} (ax+by)\)

这个问题在maspy的题解里面写的是用凸包或CHT

但是我不会geo的任何东西,于是转化成ds。

当\(b\not = 0\)时,相当不人类智慧的考虑到\(ax+by=y(\frac{x}{y}a+b)\),看作时某个位置的一次函数最值乘上一个常数,发现可以直接李超线段树维护。

note

注意一下0的情况。至少我还需要除了线段树要计所有加入a的max,所有加入a的min,所有加入且b为0的a的max,所有加入且b为0的a的min,然后在做。详细的见代码(有点丑)

code

using db = double;
inline constexpr static db eps = 1e-10;

constexpr int N = 5e4 + 5;

int n, fa[N], dsu_con_cnt = 0;
ll ans = 0, val[N], a[N], b[N];
db pos[N];
vector<int> cons[N];
pii rcs[N];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
bool merge(int u, int v) { auto du = find(u), dv = find(v); if (du != dv) return fa[du] = dv, --dsu_con_cnt, true; else return false; }

struct Line {
  ll k, b;
  Line(ll _k = inf<ll>, ll _b = 0) : k(_k), b(_b) { }
  Line& operator=(const Line&x) { k = x.k, b = x.b; return *this; }
};

struct segnode {
  Line l1, l2;
} seg[N << 2];

# define lson index << 1
# define rson index << 1 | 1

inline db calc(Line cur, db pos) {
  return static_cast<db>(cur.k) * pos + static_cast<db>(cur.b);
}

void build(int index, int l, int r) { 
  if (l > r) return ;
  seg[index].l1 = seg[index].l2 = Line(); 
  if (l == r) return ;
  int mid = (l + r) >> 1;
  build(lson, l, mid);
  build(rson, mid + 1, r);
}

void change1(int index, int l, int r, Line x) {
  if (l > r) return ;
  int mid = (l + r) >> 1;
  if (seg[index].l1.k == inf<ll> || calc(seg[index].l1, pos[mid]) < calc(x, pos[mid])) swap(seg[index].l1, x);
  if (x.k == inf<ll> || l == r) return ;
  if (calc(seg[index].l1, pos[l]) < calc(x, pos[l])) change1(lson, l, mid, x);
  if (calc(seg[index].l1, pos[r]) < calc(x, pos[r])) change1(rson, mid + 1, r, x);
}

void query1(int index, int l, int r, int qpos, Line &cur) {
  if (l > r) return ;
  int mid = (l + r) >> 1;
  if (seg[index].l1.k == inf<ll>) return;
  if (cur.k == inf<ll> || calc(cur, pos[qpos]) < calc(seg[index].l1, pos[qpos])) cur = seg[index].l1;
  if (l == r) return ;
  if (qpos <= mid) query1(lson, l, mid, qpos, cur);
  else query1(rson, mid + 1, r, qpos, cur);
}

void change2(int index, int l, int r, Line x) {
  if (l > r)return ;
  int mid = (l + r) >> 1;
  if (seg[index].l2.k == inf<ll> || calc(seg[index].l2, pos[mid]) > calc(x, pos[mid])) swap(seg[index].l2, x);
  if (x.k == inf<ll> || l == r) return ;
  if (calc(seg[index].l2, pos[l]) > calc(x, pos[l])) change2(lson, l, mid, x);
  if (calc(seg[index].l2, pos[r]) > calc(x, pos[r])) change2(rson, mid + 1, r, x);
}

void query2(int index, int l, int r, int qpos, Line &cur) {
  if (l > r) return ;
  int mid = (l + r) >> 1;
  if (seg[index].l2.k == inf<ll>) return;
  if (cur.k == inf<ll> || calc(cur, pos[qpos]) > calc(seg[index].l2, pos[qpos])) cur = seg[index].l2;
  if (l == r) return ;
  if (qpos <= mid) query2(lson, l, mid, qpos, cur);
  else query2(rson, mid + 1, r, qpos, cur);
}

struct segtree_cht {
  int sz, tot;
  bool seg1_added;
  map<pair<ll, ll>, int> idx;
  pair<ll, int> amx, amn, amx_zero, amn_zero;
  segtree_cht() { amx = mkp(-inf<ll>, -1), amn = mkp(inf<ll>, -1), amx_zero = mkp(-inf<ll>, -1), amn_zero = mkp(inf<ll>, -1); seg1_added = false; }
  void rsz(int _sz) { sz = _sz; }
  void work(ll *X, ll *Y) { 
    rep(i, 1, n) idx[mkp(X[i], Y[i])] = i; 
    rep(i, 1, n) if (Y[i]) ::pos[++tot] = db(X[i]) / db(Y[i]);
    if (tot) {
      sort(pos + 1, pos + tot + 1);
      tot = unique(pos + 1, pos + tot + 1) - pos - 1;
    }
  }
  void rst() { seg1_added = false; build(1, 1, tot); }
  void add(ll a, ll b) {
    auto _id = idx[mkp(a, b)];
    chkmax(amx, mkp(a, _id)), chkmin(amn, mkp(a, _id));
    if (!b) {
      auto _id = idx[mkp(a, b)];
      chkmax(amx_zero, mkp(a, _id)), chkmin(amn_zero, mkp(a, _id));
    }
    change1(1, 1, tot, Line(a, b));
    seg1_added = true;
    change2(1, 1, tot, Line(a, b));
  }
  ll query_max(ll x, ll y) {
    if (!seg1_added) return -inf<ll>;
    if (!y) {
      if (x >= 0) return x * amx.first;
      else return x * amn.first;
    }
    int p = lower_bound(pos + 1, pos + tot + 1, db(x) / y) - pos;
    Line tans;
    tans.k = inf<ll>;
    if (y >= 0) query1(1, 1, tot, p, tans);
    else query2(1, 1, tot, p, tans);
    return tans.k * x + tans.b * y;
  }
  pair<ll, int> query_max_with_id(ll x, ll y) {
    if (!seg1_added) return mkp(-inf<ll>, -1);
    if (!y) {
      if (x >= 0) return mkp(x * amx.first, amx.second);
      else return mkp(x * amn.first, amn.second);
    }
    int p = lower_bound(pos + 1, pos + tot + 1, db(x) / y) - pos;
    Line tans;
    tans.k = inf<ll>;
    if (y > 0) query1(1, 1, tot, p, tans);
    else query2(1, 1, tot, p, tans);
    pair<ll, int> curans = mkp(tans.k * x + tans.b * y, idx[mkp(tans.k, tans.b)]);
    if (x >= 0) {
      if (amx_zero.first != -inf<ll>) chkmax(curans, mkp(x * amx_zero.first, amx_zero.second));
    } else {
      if (amn_zero.first != inf<ll>) chkmax(curans, mkp(x * amn_zero.first, amn_zero.second));
    }
    return curans;
  }
  ll query_min(ll x, ll y) {
    return -query_max(-x, -y);
  }
  pair<ll, int> query_min_with_id(ll x, ll y) {
    auto ret = query_max_with_id(-x, -y);
    return mkp(-ret.first, ret.second);
  }
};

segtree_cht T;

signed main() { 
  read(n); T.rsz(n);
  iota(fa + 1, fa + n + 1, 1);
  dsu_con_cnt = n;
  rep(i, 1, n) read(a[i]);
  rep(i, 1, n) read(b[i]);
  T.work(a, b);
  while(dsu_con_cnt > 1) {
    bool flag = false;
    rep(i, 1, n) cons[i].clear();
    rep(i, 1, n) cons[find(i)].eb(i);
    fill(val + 1, val + n + 1, inf<ll>);
    fill(rcs + 1, rcs + n + 1, mkp(0, 0));
    T.rst();
    rep(u, 1, n) {
      for(auto v : cons[u]) {
        auto [tv, w] = T.query_min_with_id(a[v], b[v]);
        // dbg(u, v, w, tv);
        if (val[u] > tv) val[u] = tv, rcs[u] = mkp(v, w);
      }
      for (auto v : cons[u]) 
        T.add(a[v], b[v]);
    }
    T.rst();
    per(u, n, 1) {
      for(auto v : cons[u]) {
        auto [tv, w] = T.query_min_with_id(a[v], b[v]);
        // dbg(u, v, w, tv);
        if (val[u] > tv) val[u] = tv, rcs[u] = mkp(v, w);
      } 
      for (auto v : cons[u]) 
        T.add(a[v], b[v]);
    }
    rep(i, 1, n) {
      auto [u, v] = rcs[i];
      if (!u) continue;
      if (merge(u, v)) {
        flag = true;
        ans += val[i];
      }
    }
    if (!flag) break;
  }
  writeln(ans);

#if defined(LOCAL) && !defined(CPH)
  std::cerr << "Spend Time : " << clock() * 1. / CLOCKS_PER_SEC * 1e3 << " ms \n";
#endif
  return 0;
} 

后来发现我的想法和maspy的基本相同,而李超树写法好像比maspy的CHT板子跑的快!

标签:index,return,int,pos,sol,mkp,inf,pakencamp,day1
From: https://www.cnblogs.com/georgeyucjr/p/18447329

相关文章

  • day11[Lagent 自定义你的 Agent 智能体]
    环境配置开发机选择30%A100,镜像选择为Cuda12.2-conda。首先来为Lagent配置一个可用的环境。LagentWebDemo使用使用Lagent的WebDemo来体验InternLM2.5-7B-Chat的智能体能力先使用LMDeploy部署InternLM2.5-7B-Chat,并启动一个APIServer然后,我们在另一个......
  • 【题解】Solution Set - NOIP2024集训Day42 博弈论
    【题解】SolutionSet-NOIP2024集训Day42博弈论https://www.becoder.com.cn/contest/5574https://www.cnblogs.com/CloudWings/p/17813917.html「中山市选2009」谁能赢呢?一道经典的「二分图博弈」在棋盘问题上的应用。https://www.luogu.com.cn/article/h8a79k3i......
  • openzeppelin/contracts/utils/Counters.sol" not found
    运行以下//SPDX-License-Identifier:MITpragmasolidity0.7.5;import{Counters}from"@openzeppelin/contracts/utils/Counters.sol";contractMyTokenisERC721,Pausable,Ownable{usingCountersforCounters.Counter;Counters.Cou......
  • CF2018E2 Solution
    CF2018E2Solution先考虑E1的做法。首先我们如果钦定一组\(k\)条线段的话,容易求出最大组数。简单来讲就是将所有端点按照右端点排序,这样只需要考虑一个偏序,然后扫描,将区间\([l_i,r_i]\)加一,当发现某个点的值为\(k\)时,就说明分成了一组方案。此时我们一定清空,然后记录当......
  • Solution - Atcoder ARC157E XXYX Binary Tree
    考虑这个不存在\(\texttt{YY}\)的限制,与\(\texttt{XX}\)个数为变量的限制相比较,看起来\(\texttt{Y}\)就更特殊,于是考虑从\(\texttt{Y}\)的视角来分析问题。同时考虑到因为有\(A+B+C=n-1\),所以\(\texttt{XX}\)其实也不是很重要,因为只需要让\(\texttt{XY}\)和......
  • Solution - Atcoder ARC157D YY Garden
    考虑到因为有横轴数轴两部分的限制,不妨先固定下来一部分的限制再处理另一部分。对于这题来说横轴竖轴本质是相同的,于是不妨考虑固定横轴。如果知道了横轴的分割,那么对于竖轴上就可以根据分割情况知道合法的分割了。即考虑记\(f_i\)为考虑了竖轴的前\(i\)列,第\(i\)列为最......
  • DAY1-补题
    说句闲话:研究补题最好的方式是补完AK了,祝你们成功(滑稽此文章仅作为补题,题解等我理解完掉重新写。比赛情况不可饶恕的错误(滑稽赛时第一题看错题意,导致明明可以做掉的内容爆了,T2考虑到了正解,可一直在推式子和打表中间晃荡,遗憾。T3很好笑,没有删除调试语句,赛后删了重交过到了30pt......
  • 【牛客训练记录】2024牛客国庆集训派对day1
    https://ac.nowcoder.com/acm/contest/90188#question赛后反思好像没有,全场只做出来一题QAQJ题想在图上找到同色三角形,我们枚举至少是\(O(n^3)\)的,所以我们考虑容斥定理(?),去找异色三角形,因为只要保证一条边上两点颜色不一样,另找一点随便都可以,所以我们只要统计白色的点数,......
  • 代码随想录算法训练营Day17 | 654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜
    目录654.最大二叉树617.合并二叉树700.二叉搜索树中的搜索98.验证二叉搜索树654.最大二叉树题目654.最大二叉树-力扣(LeetCode)给定一个不重复的整数数组nums。最大二叉树可以用下面的算法从nums递归地构建:创建一个根节点,其值为nums中的最大值。递归地在......
  • [雅礼集训 2017 Day1]市场 题解
    题目链接题目分析听说是很典的一道题,很明显难点在于除法下取整的操作。类似花神那一道题,但是由于有区间加,所以无法进行暴力修改。很明显暴力复杂度爆炸,考虑下取整带来的性质:对于一对相邻的数,很明显有\(\lfloor\frac{x-1}{k}\rfloor\le\lfloor\frac{x}{k}\rfloor-1\)。......