【分块】CODEFORCES 384C Subset Sums

通道

题意:给出n个数,m组序列,然后每次可以选择一个序列给对应的每个数加定值,及询问该组对应数之和

思路:可以知道修改某一组后,肯定对应和其他组有相交部分也要对应修改,每次去修改肯定不现实,然后对于sqrt(n)以内的数可以O(n)修改,其他的只要计算对应的增量即可,然后维护对于大于sqrt(n)的序列会影响到哪些小于sqrt(n)的序列即可。

代码:

#include <cstdio>
#include  <cmath>
#include <vector>
using namespace std;

typedef long long ll;
const int N = 100005;
const int M = 333;

int n , m , q;
int size[N], id[N];
int bigcnt = 0, vis[N];
int inter[N][M];
ll a[N];
ll ans[N] , update[N];   
vector<int> num[N];

int main() {  
    scanf("%d%d%d" , &n , &m , &q);
    for (int i = 1 ; i <= n ; i ++) {
        scanf ("%I64d" , &a[i]);
    }
    int limit = (int)sqrt (n) + 1;
    for (int i = 1 ; i <= m ; i ++) {
        scanf ("%d" , &size[i]);
        num[i].resize(size[i]);
        for (int j = 0 ; j < size[i] ; j ++) {
            scanf ("%d" , &num[i][j]);
        }
        if (size[i] >= limit) {
            id[i] = bigcnt++;
        } else id[i] = -1;
    }
    for (int i = 1 ; i <= m ; i ++) 
        if (id[i] != -1) {
            for (int j = 0 ; j < size[i] ; j ++) {
                vis[num[i][j]] = i;
                ans[id[i]] += a[num[i][j]];
            }
            for (int j = 1 ; j <= m ; j ++) {
                for (int k = 0 ; k < size[j] ; k ++)
                    if (vis[num[j][k]] == i)
                        inter[j][id[i]]++;
            }
        }
    while (q --) {
        char str[5];int idx;
        scanf ("%s%d" , str , &idx);
        if (str[0] == '?') {
            if (id[idx] == -1) {
                ll ret = 0;
                for (int i = 0 ; i < size[idx] ; i ++)
                    ret += a[num[idx][i]];
                for (int i = 0 ; i < bigcnt ; i ++) 
                    ret += 1LL * update[i] * inter[idx][i];
                printf ("%I64d\n" , ret);
            } else printf ("%I64d\n" , ans[id[idx]]);
        } else {
            int x; scanf ("%d" , &x);
            for (int i = 0 ; i < bigcnt ; i ++) 
                ans[i] += 1LL * inter[idx][i] * x;
            if (id[idx] == -1) {
                for (int i = 0 ; i < size[idx] ; i ++)
                    a[num[idx][i]] += x;
            } else update[id[idx]] += x;
        }
    }
    return 0;
}
View Code

 

posted @ 2015-08-17 20:09  mithrilhan  阅读(252)  评论(0编辑  收藏  举报