Codeforces 348C - Subset Sums(根号分治)
对于这类不好直接维护的数据结构,第一眼应该想到……
根号分治!
我们考虑记【大集合】为大小 \(\geq\sqrt{n}\) 的集合,【小集合】为大小 \(<\sqrt{n}\) 的集合。
显然,查询/修改小集合的时候,直接暴力跑一遍不会出问题,时间复杂度 \(\mathcal O(n\sqrt{n})\)。
关键在于怎样处理【大集合】:
- 修改大集合的时候,暴力一个一个元素修改显然不行,于是考虑整体打一个 \(+v\) 的标记 \(tag_x\)
- 查询大集合的时候我们也不能遍历一遍集合求和,于是可以维护一个数组 \(ans_x\) 表示大集合 \(x\) 的答案,查询的时候直接输出 \(ans_x\)。
这样又有一个问题了,怎样将大集合的贡献累加入答案中。
注意到大集合有一个性质,那就是大集合的个数不会超过 \(\sqrt{n}\)。
故每一次集合整体加值的时候,暴力修改每个大集合的 \(ans_x\);询问小集合的时候,将每个大集合的 \(tag_x\) 累加进答案中。
至于怎样计算大集合的贡献,可以维护一个 \(same_{i,j}\) 表示第 \(i\) 个大集合与第 \(j\) 个集合有多少个公共的元素。那么你对某个大集合 \(x\) 做一次 \(+v\) 的操作,它对另一个集合 \(y\) 的贡献应为 \(same_{x,y}\times v\)。
总结下来,就是:
- 修改小集合 \(x\),暴力修改 \(a_i\),并且对于所有大集合 \(y\),令 \(ans_y\) 假设 \(same_{y,x}\times v\)。
- 修改大集合 \(x\),令 \(tag_x\) 加上 \(v\),并且对于所有大集合 \(y\),令 \(ans_y\) 假设 \(same_{y,x}\times v\)。
- 查询小集合 \(x\),暴力遍历一遍集合求出 \(a_i\) 的和,并枚举所有大集合 \(y\),令答案加上 \(same_{y,x}\times tag_y\)。
- 查询大集合 \(x\),直接输出 \(ans_x\) 就行了。
时空复杂度均为 \(n\sqrt{n}\)
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=1;
while(!isdigit(c)){if(c=='-') neg=-1;c=getchar();}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
x*=neg;
}
const int MAXN=1e5;
const int SQRT=316;
int n,m,qu;ll a[MAXN+5];
vector<int> s[MAXN+5];
int bg[SQRT+5],bgnum=0,same[MAXN+5][SQRT+5];
bitset<MAXN+5> vis[SQRT+5];
ll anss[MAXN+5],add[MAXN+5];
int main(){
scanf("%d%d%d",&n,&m,&qu);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=m;i++){
int len;scanf("%d",&len);
for(int j=1;j<=len;j++){
int x;scanf("%d",&x);s[i].pb(x);
anss[i]+=a[x];
}
if(len>=SQRT){
bg[++bgnum]=i;
for(int j=0;j<s[i].size();j++){
vis[bgnum][s[i][j]]=1;
}
}
}
for(int i=1;i<=m;i++)
for(int j=0;j<s[i].size();j++)
for(int k=1;k<=bgnum;k++)
if(vis[k][s[i][j]]) same[i][k]++;
while(qu--){
static char opt[3];scanf("%s",opt+1);
if(opt[1]=='?'){
int x;scanf("%d",&x);
ll ans=0;
if(s[x].size()<SQRT){
for(int j=0;j<s[x].size();j++) ans+=a[s[x][j]];
for(int j=1;j<=bgnum;j++) ans+=1ll*add[bg[j]]*same[x][j];
printf("%lld\n",ans);
} else printf("%lld\n",anss[x]);
} else {
int x,y;scanf("%d%d",&x,&y);
if(s[x].size()<SQRT){
for(int j=0;j<s[x].size();j++) a[s[x][j]]+=y;
for(int j=1;j<=bgnum;j++) anss[bg[j]]+=1ll*y*same[x][j];
} else {
for(int j=1;j<=bgnum;j++) anss[bg[j]]+=1ll*y*same[x][j];
add[x]+=y;
}
}
}
return 0;
}
Codeforces 348C - Subset Sums(根号分治)的更多相关文章
- CodeForces 348C Subset Sums(分块)(nsqrtn)
C. Subset Sums time limit per test 3 seconds memory limit per test 256 megabytes input standard inpu ...
- Codeforces 348C Subset Sums 分块思想
题意思路:https://www.cnblogs.com/jianrenfang/p/6502858.html 第一次见这种思路,对于集合大小分为两种类型,一种是重集合,一种是轻集合,对于重集合,我们 ...
- Codeforces 1039D You Are Given a Tree [根号分治,整体二分,贪心]
洛谷 Codeforces 根号分治真是妙啊. 思路 考虑对于单独的一个\(k\)如何计算答案. 与"赛道修建"非常相似,但那题要求边,这题要求点,所以更加简单. 在每一个点贪心地 ...
- [codeforces 509]C. Sums of Digits
[codeforces 509]C. Sums of Digits 试题描述 Vasya had a strictly increasing sequence of positive integers ...
- 洛谷P1466 集合 Subset Sums
P1466 集合 Subset Sums 162通过 308提交 题目提供者该用户不存在 标签USACO 难度普及/提高- 提交 讨论 题解 最新讨论 暂时没有讨论 题目描述 对于从1到N (1 ...
- Project Euler 106:Special subset sums: meta-testing 特殊的子集和:元检验
Special subset sums: meta-testing Let S(A) represent the sum of elements in set A of size n. We shal ...
- Project Euler P105:Special subset sums: testing 特殊的子集和 检验
Special subset sums: testing Let S(A) represent the sum of elements in set A of size n. We shall cal ...
- Project Euler 103:Special subset sums: optimum 特殊的子集和:最优解
Special subset sums: optimum Let S(A) represent the sum of elements in set A of size n. We shall cal ...
- Codeforces348C - Subset Sums
Portal Description 给出长度为\(n(n\leq10^5)\)的序列\(\{a_n\}\)以及\(m(m\leq10^5)\)个下标集合\(\{S_m\}(\sum|S_i|\leq ...
随机推荐
- 【UE4 C++ 基础知识】<3> 基本数据类型、字符串处理及转换
基本数据类型 TCHAR TCHAR就是UE4通过对char和wchar_t的封装 char ANSI编码 wchar_t 宽字符的Unicode编码 使用 TEXT() 宏包裹作为字面值 TCHAR ...
- 2021.8.15考试总结[NOIP模拟40]
T1 送花 线段树.枚举右端点,线段树记录左端点对应的值. 每次对当前颜色上上次出现的位置到上次出现的位置区间减,上次出现的位置到当前位置区间加. $code:$ 1 #include<bits ...
- SpringCloud微服务实战——搭建企业级开发框架(十):使用Nacos分布式配置中心
随着业务的发展.微服务架构的升级,服务的数量.程序的配置日益增多(各种微服务.各种服务器地址.各种参数),传统的配置文件方式和数据库的方式已无法满足开发人员对配置管理的要求: 安全性:配置跟随源代码保 ...
- (类)Program1.1
1 class MyClass: 2 3 i = 12345 4 5 def __init__(self): 6 self.data = "WOOWOWOWO" 7 8 def f ...
- sort命令的学习与实践
一.用man sort 查看sort的帮助文档 *sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出. [rocrocket@ro ...
- hdu 2860 Regroup(并查集)
题意: AP x yA recruit with ability rate x were asked to join company y. (0<=x<2^31, 0<=y<n ...
- 绚丽的色彩从何而来_LOTO示波器实测WS2812B系LED光源
绚丽的色彩从何而来_LOTO示波器实测WS2812B系LED光源 不管你对 "RGB性能狂升300%" 的梗认同不认同,不可否认,绚丽的彩色很是酷炫,在现在市面上带"灯& ...
- Linux环境下安装中山大学东校区iNode客户端
在中山大学登录校园网有两种方式,一种是连接WiFi,另一种是连接网线.这两种上网方式都需要用到NetID,但是连接网线的话还需要使用到iNode客户端(指东校区). Windows下iNode客户端的 ...
- .Net Minimal Api 介绍
Minimal API是.Net 6中新增的模板,借助C# 10的一些特性以最少的代码运行一个Web服务.本文脱离VS通过VS Code,完成一个简单的Minimal Api项目的开发. 创建项目 随 ...
- Spring Cloud Alibaba 使用Seata解决分布式事务
为什么会产生分布式事务? 随着业务的快速发展,网站系统往往由单体架构逐渐演变为分布式.微服务架构,而对于数据库则由单机数据库架构向分布式数据库架构转变.此时,我们会将一个大的应用系统拆分为多个可以独立 ...