CodeForces 348 C.Subset Sums(分块)

Description
一个长度为n的序列a[i]和m个集合Si,每个集合都用一些编号表示,这些编号对应的是序列中的元素,有两种操作:
1.查询第k个集合中元素之和
2.把第k个集合中对应a序列中的元素全部加上x
Input
第一行三个整数n,m,q分别表示序列长度,集合数和操作数,之后n个整数a[i]表示该序列,之后m行第i行首先输入一个整数num表示第i个集合的元素个数,然后输入num个编号对应a序列中的num个元素,最后q行每行表示一个操作,? k表示查询第k个集合中元素之和,+ k x表示把第k个集合中对应a序列中的元素全部加上x
(1<=n,m,q<=1e5,|a[i]|<=1e8,|x|<=1e8,保证m个集合中元素之和不超过1e5)
Output
对于每次查询操作输出一个答案
Sample Input
5 3 5
5 -5 5 1 -4
2 1 2
4 2 1 4 5
2 2 5
? 2
+ 3 4
? 1
+ 2 1
? 2
Sample Output
-3
4
9
Solution
把集合分类,称元素个数超过sqrt(n)的集合为重集合,不超过sqrt(n)的集合为轻集合,轻集合直接更新,重集合记录更新值,记录第i个集合与第j个重集合的交集元素个数cnt[i][j],第i个重集合中元素之和sum[i],第i个重集合中元素的更新值add[i],对轻重集合的两种操作:
第i个轻集合更新:直接更新该集合对应的a序列元素,然后更新重集合的sum值,第j个重集合的sum[j]+=x*cnt[i][j],时间复杂度O(sqrt(n))
第i个重集合更新:累加更新值,add[i]+=x,时间复杂度O(1)
第i个轻集合查询:直接累加该集合对应的a序列元素,然后把重集合延迟的更新累加,即累加上cnt[i][j]*add[j],时间复杂度O(sqrt(n))
第i个重集合查询:本身的值累加上重集合延迟的更新,即sum[i]+cnt[i][j]*add[j],时间复杂度O(sqrt(n))
这样q次操作时间复杂度为O(qsqrt(n))
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 111111
int n,m,q;
ll a[maxn];
int h[maxn];//h[i]=1:第i个集合是重集合,h[i]=0:第i个集合是轻集合  
int cnt[maxn][356];//cnt[i][j]是第i个集合和第j个重集合的交集元素个数 
int res,id[maxn];//res表示重集合的数量,id[i]表示第i个重集合的编号 
ll sum[maxn];//sum[i]表示第i个集合(重)中元素总和 
ll add[maxn];//add[i]表示第i个集合(重)中元素更新值 
vector<int>g[maxn],gg[maxn];//g[i]表示第i个集合,gg[i]表示第i个元素所在集合 
int main()
{
    while(~scanf("%d%d%d",&n,&m,&q))
    {
        for(int i=1;i<=n;i++)scanf("%I64d",&a[i]);
        memset(cnt,0,sizeof(cnt));
        memset(sum,0,sizeof(sum));
        memset(add,0,sizeof(add));
        for(int i=1;i<=m;i++)g[i].clear();
        for(int i=1;i<=n;i++)gg[i].clear();
        int nn=sqrt(n+0.5),res=0;
        for(int i=1;i<=m;i++)
        {
            int num,temp;
            scanf("%d",&num);
            if(num>=nn)h[i]=1,id[++res]=i;
            else h[i]=0;
            for(int j=0;j<num;j++)
            {
                scanf("%d",&temp);
                g[i].push_back(temp); 
                if(h[i])sum[i]+=a[temp],gg[temp].push_back(res);
            }
        } 
        for(int i=1;i<=m;i++)
            for(int j=0;j<g[i].size();j++)
            {
                int u=g[i][j];
                for(int k=0;k<gg[u].size();k++)
                {
                    int v=gg[u][k];
                    cnt[i][v]++;
                }
            }
        while(q--)
        {
            int k,x;
            char op[3];
            scanf("%s%d",op,&k);
            if(op[0]=='?')
            {
                ll ans=0;
                if(h[k])
                {
                    ans=sum[k];
                    for(int i=1;i<=res;i++)ans+=add[id[i]]*cnt[k][i];
                }
                else
                {
                    for(int i=0;i<g[k].size();i++)ans+=a[g[k][i]];
                    for(int i=1;i<=res;i++)ans+=add[id[i]]*cnt[k][i];
                }
                printf("%I64d\n",ans);
            }
            else
            {
                scanf("%d",&x);
                if(h[k])add[k]+=x;
                else
                {
                    for(int i=0;i<g[k].size();i++)a[g[k][i]]+=x;
                    for(int i=1;i<=res;i++)
                        sum[id[i]]+=x*cnt[k][i];
                }
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源码+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非常有意义的。 本文从管理员、用户的功能要求出发,4S店客户管理系统的功能模块主要是实现管理员服务端;首页、个人心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需求相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流信息的查看及回复相应操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值