首页 > 代码库 > CF348C Subset Sums
CF348C Subset Sums
思路好题
首先,将集合大小大于等于sqrt(n)的集合称为重集合,其余称为轻集合,则重集合个数小于等于sqrt(n)。
令f[i][j]表示第i个集合和第j个集合的同样元素个数,这能够在O(n*sqrt(n))内预处理。
再令sum[i]表示第i个重集合的元素和,add[i]表示第i个重集合全部元素的增量标记。
改动操作。重集合直接改动sum[i]和add[i]。轻集合暴力改动,同一时候用f[i][j]改动重集合。
询问操作。重集合直接输出sum[i],轻集合暴力计算。
总复杂度O(n*sqrt(n))。
注意集合的存储方式。邻接矩阵会超内存。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> #define F(i,j,n) for(int i=j;i<=n;i++) #define D(i,j,n) for(int i=j;i>=n;i--) #define ll long long #define maxn 100005 using namespace std; int n,m,q,cnt,tot,block,head[maxn],id[maxn],f[maxn][400]; ll a[maxn],sum[400],add[400]; bool g[400][maxn]; struct edge_type{int next,to;}e[maxn]; inline int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void add_edge(int x,int y) { e[++cnt]=(edge_type){head[x],y}; head[x]=cnt; } int main() { n=read();m=read();q=read(); block=ceil(sqrt(100000)); F(i,1,n) a[i]=read(); F(i,1,m) { int sz=read(); if (sz>=block) id[i]=++tot; while (sz--) { int x=read(); if (id[i]) g[tot][x]=true; add_edge(i,x); } } F(i,1,m) F(j,1,tot) for(int k=head[i];k;k=e[k].next) if (g[j][e[k].to]) f[i][j]++; F(i,1,m) if (id[i]) for(int j=head[i];j;j=e[j].next) sum[id[i]]+=a[e[j].to]; while (q--) { char ch=getchar();while (ch!='?'&&ch!='+') ch=getchar(); if (ch=='?') { int x=read(); if (id[x]) printf("%I64d\n",sum[id[x]]); else { ll ans=0; for(int i=head[x];i;i=e[i].next) ans+=a[e[i].to]; F(i,1,tot) ans+=add[i]*f[x][i]; printf("%I64d\n",ans); } } else { int x=read(),y=read(); F(i,1,tot) sum[i]+=(ll)y*f[x][i]; if (id[x]) add[id[x]]+=y; else for(int i=head[x];i;i=e[i].next) a[e[i].to]+=y; } } }
CF348C Subset Sums
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。