CodeForces 348C Subset Sums nsqrtn的姿势。。

来源:互联网 发布:歧视 知乎 编辑:程序博客网 时间:2024/06/06 17:32

题意:

给n个数和m个集合, 一个集合就是n个数的下标。

有q个操作, 每个操作就是给一个集合里面代表的数加上v, 或者询问一个集合里面的数的和。


解法:

ORZ题解。。。

设B = sqrtn

先给集合分成两种, 一种是大小大于B的, 称为重集合, 小于的称为轻集合。

显然重集合的个数不会超过B个。

对每个集合, 求出它和每个重集合交集的大小, 即cnt[i][j]表示第i个集合和第j 个重集合交集的大小。 cnt数组可以O(NB)求出

对每个重集合, 维护add和sum, add表示加在这个集合上的值, sum表示这个集合没有加上其他重集合的附加值的和。


然后把操作分为4种:

1. 在轻集合上加值。 这样对每个轻集合里面的元素暴力加上v就行(O(B))。 同时要维护重集合的sum, 于是, 每个重集合的sum加上v*cnt[i][j],(O(B))。复杂度(O(B))。

2. 在重集合上加值。 直接在重集合的add上加上v。 (O(1))

3. 询问轻集合。 ans 加上轻集合里面的元素的值, (O(B))。 然后再加上重集合的add[j] * cnt[i][j], (O(B))。 O(B)

4. 询问重集合。 ans 加上重集合的sum, 然后再加上各个重集合的add[j] * cnt[i][j]。 O(B)


#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <vector>using namespace std;#define mnx 110020#define B 350#define LL long long#define PB push_back#define vi vector<int>LL add[B], sum[B];int id[mnx]; //第i个集合的重集合标号int cnt[mnx][B], c[mnx];LL tot[mnx];bool h[mnx]; // 第i个集合是不是重集合vi g[mnx];   //集合vi t[mnx];    // 第i个数被哪些重集合包括int n, m, q, k;int main() {while(scanf("%d%d%d", &n, &m, &q) != EOF) {for(int i = 0; i < n; ++i) scanf("%I64d", &tot[i]);k = 0;for(int i = 0; i < m; ++i) {scanf("%d", &c[i]);if(c[i] >= B) {h[i] = 1;id[i] = k++;}else h[i] = 0;for(int j = 0; j < c[i]; ++j) {int u;scanf("%d", &u);--u;g[i].PB(u);if(h[i]) {  // 重集合的话在包括u的重集合中加上k-1t[u].PB(k - 1);sum[k-1] += tot[u];}}}//memset(cnt, 0, sizeof cnt);for(int i = 0; i < m; ++i) {for(int j =  0; j < g[i].size(); ++j) {int u = g[i][j];   //第i个集合包含的下标for(int kk = 0; kk < t[u].size(); ++kk) {int v = t[u][kk];  //重集合cnt[i][v]++;}}}while(q--) {char op[4];int p;LL x;scanf("%s%d", op, &p);--p;if(op[0] == '?') {LL ans = 0;if(h[p]) {ans += sum[id[p]];for(int i = 0; i < k; ++i)ans += cnt[p][i] * add[i];}else {for(int i = 0; i < g[p].size(); ++i) {ans += tot[g[p][i]];}for(int i = 0; i < k; ++i)ans += cnt[p][i] * add[i];}printf("%I64d\n", ans);}else {scanf("%I64d", &x);if(h[p]) {add[id[p]] += x;}else {for(int i = 0; i < g[p].size(); ++i)tot[g[p][i]] += x;for(int i = 0; i < k; ++i)sum[i] += cnt[p][i] * x;}}}}return 0;}



0 0