2 条题解
-
2
S001B. 催化剂
给定一个长度为 的序列 , 位置表示有一个种类为 的糖果( 可以重复,即同一个种类有多个糖果),接下来有 次查询:
1 x:表示种类 多了 个糖果2 x:表示种类 少了 个糖果3 k:输出将所有糖果分给 个小朋友的最小愤怒值之和- 愤怒值:令第 个小朋友所拥有的第 种糖果的数量为 ,则愤怒值之和为
若第 种糖果的数量为 ,则对于 个小朋友,最小愤怒值为 ,其实就是每种糖果平均分给 个小朋友,可以证明这是最优的。比如说:糖果为 , 个小朋友,划分方案如下。
第一个小朋友 第二个小朋友 那么,问题转化为了动态求出现所有出现次数 的数的和 出现次数 的数的个数。这个是可以通过平衡树来维护的,不过难写且麻烦。
不妨考虑将询问离线,对于一次更改,相当于对所有 询问作统一的更改( 表示当前更改后该糖果种类的数量)。故,考虑将询问排序,每次更改通过树状数组实现即可。
signed main() { cin.tie(0); cout.tie(0); ios::sync_with_stdio(0); cin >> n >> q; int op, x; for (int i = 1; i <= n; i ++) cin >> x, opr[ ++ m] = {x, 1}; while (q -- ) { cin >> op >> x; if (op == 1) opr[ ++ m] = {x, 1}; else if (op == 2) opr[ ++ m] = {x, -1}; else k ++, qry[k] = {x, k}, upd[m].push_back(k); } sort(qry + 1, qry + 1 + k); for (int i = 1; i <= k; i ++) pos[qry[i].se] = i; for (int i = 1; i <= m; i ++) { sum.add(lst[opr[i].fi], -tot[opr[i].fi]); tot[opr[i].fi] += opr[i].se; cnt.add(lst[opr[i].fi], -1); int l = 1, r = k, ans = -1; while (l <= r) { int mid = l + r >> 1; if (qry[mid].fi < tot[opr[i].fi]) l = mid + 1, ans = mid; else r = mid - 1; } if (ans == -1) lst[opr[i].fi] = 0; else lst[opr[i].fi] = k - ans + 1, sum.add(lst[opr[i].fi], tot[opr[i].fi]), cnt.add(lst[opr[i].fi], 1); for (auto v : upd[i]) res[v] = sum.sum(k - pos[v] + 1) - qry[pos[v]].fi * cnt.sum(k - pos[v] + 1); } for (int i = 1; i <= k; i ++) cout << res[i] << endl; return 0; } -
1
T2:催化剂
思路
我们能发现,对于每次查找,若有一种糖果类型的糖果数超过 ,则它一定会积累最终的答案。
所以,我们需要将每类糖果先给每个小朋友一个,其余的都给一个小朋友即可。
这样一来,问题就转变为了计算:
- 为糖果数量大于 的糖果类型的总糖果数量有多少。
- 为糖果数量大于 的糖果类型的糖果数量之和。
- 与题意相同。
解题方法
我们使用树状数组进行维护,一个负责找到超过 的糖果类型有几个,另一个负责找到超过 的糖果类型的总糖果数量有多少。
简单的说,一个在变动时只是
+1和-1的变化,另一个则是+x和-x的变化。Code
#include <bits/stdc++.h> #define ll long long using namespace std; long long n,m; long long c[1000011*6],a; ll p[1000011]; ll cs[1000011*6]; long long lowbit(long long x){ return x&(-x); } long long getsun(long long x){ if(!x) return 0; long long sum=0; for(long long i=x;i;i-=lowbit(i)) sum+=c[i]; return sum; } void update(long long x,long long y){ if(!x) return ; for(long long i=x;i<=2300000;i+=lowbit(i)){ c[i]+=y; } } long long lowbits(long long x){ return x&(-x); } long long getsuns(long long x){ if(!x) return 0; long long sum=0; for(long long i=x;i;i-=lowbits(i)) sum+=cs[i]; return sum; } void updates(long long x,long long y){ if(!x) return ; for(long long i=x;i<=2300000;i+=lowbits(i)){ cs[i]+=y; } } // 直接粘贴,懒 int main(){ cin >>n >>m; for(long long i=1;i<=n;i++){ ll x; scanf("%lld",&x); updates(p[x]+1,p[x]+1); update(p[x]+1,1); updates(p[x],-p[x]); update(p[x],-1); p[x]++; } while(m--){ int op; scanf("%d",&op); if(op==1){ long long x; scanf("%lld",&x); update(p[x]+1,1); updates(p[x]+1,p[x]+1); update(p[x],-1); updates(p[x],-p[x]); p[x]++; }else if(op==2){ ll x; cin >>x; update(p[x],-1); updates(p[x],-p[x]); update(p[x]-1,1); updates(p[x]-1,p[x]-1); p[x]--; }else{ long long x; scanf("%lld",&x); cout <<getsuns(2000000)-getsuns(x)-(getsun(2000000)-getsun(x))*x <<'\n'; } } return 0; }
- 1
信息
- ID
- 3
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 4
- 标签
- 递交数
- 294
- 已通过
- 46
- 上传者