题意:
给一长度为n的序列a[],给定m个大小为$k_i$的正整数的集合,集合内元素 $x_i≤n$ 且不重复。
给定两种操作:
1.输入x,y,对于所有的 $a(i) (i ∈ Sx)$ 加上 y。
2.输入x,求$sum_{i=1}^{k_x}{a(S_{x,i})}$
解法:
将集合分类,分为大于$sqrt n$的集合和小于$sqrt n$的集合。
考虑4种情况:
1.大于$sqrt n$的集合对小于$sqrt n$的集合的贡献。
2.大于$sqrt n$的集合对大于$sqrt n$的集合的贡献。
3.小于$sqrt n$的集合对大于$sqrt n$的集合的贡献。
4.小于$sqrt n$的集合对小于$sqrt n$的集合的贡献。
对于情况1,2,3我们只要记录对于所有集合有多少个大于$sqrt n$的集合和它有元素重合 且 算出重合多少个元素。
对于情况 4 直接维护一个数组即可。
总效率$O(n sqrt n)$
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <cmath> 6 7 using namespace std; 8 9 #define N 100010 10 #define LL long long 11 typedef pair<int,int> PII; 12 #define fir first 13 #define sec second 14 #define SIZE 320 15 16 int n,m,q; 17 int siz[N],bblc[N],sblc[N],totb,tots; 18 LL a[N],ans[N],add[N],addi[N]; 19 bool v[N]; 20 vector<int> c[N]; 21 vector<PII> g[N]; 22 23 int main() 24 { 25 while(~scanf("%d%d%d",&n,&m,&q)) 26 { 27 for(int i=1;i<=n;i++) scanf("%I64d",&a[i]); 28 //int SIZE = (int)sqrt(n+0.5); 29 totb=tots=0; 30 for(int i=1;i<=m;i++) g[i].clear(); 31 for(int i=1,k,x;i<=m;i++) 32 { 33 scanf("%d",&k); 34 add[i]=0; 35 siz[i]=k; 36 if(k>=SIZE) bblc[++totb]=i; 37 else sblc[++tots]=i; 38 c[i].clear(); 39 ans[i]=0; 40 while(k--) 41 { 42 scanf("%d",&x); 43 c[i].push_back(x); 44 ans[i]+=a[x]; 45 } 46 } 47 for(int i=1,x;i<=totb;i++) 48 { 49 x=bblc[i]; 50 for(int j=0;j<siz[x];j++) v[c[x][j]]=1; 51 for(int y=1;y<=m;y++) 52 { 53 int tmp=0; 54 for(int k=0;k<siz[y];k++) 55 if(v[c[y][k]]) tmp++; 56 if(tmp) 57 { 58 if(siz[y]>=SIZE) 59 g[x].push_back(make_pair(y,tmp)); 60 else 61 g[y].push_back(make_pair(x,tmp)); 62 } 63 } 64 for(int j=0;j<siz[x];j++) v[c[x][j]]=0; 65 } 66 char ch; 67 int x,y; 68 while(q--) 69 { 70 while(ch=getchar(),ch!='?'&&ch!='+'); 71 scanf("%d",&x); 72 if(ch=='?') 73 { 74 if(siz[x]>=SIZE) 75 { 76 LL ansv=ans[x]; 77 int nl=g[x].size(); //big->big 78 for(int i=0;i<nl;i++) 79 ansv+=add[g[x][i].fir]*(LL)g[x][i].sec; 80 printf("%I64d ",ansv); 81 } 82 else 83 { 84 LL ansv=ans[x]; 85 int nl=g[x].size(); 86 for(int i=0;i<nl;i++) //big->small 87 ansv+=add[g[x][i].fir]*(LL)g[x][i].sec; 88 nl=c[x].size(); //small->small2 89 for(int i=0;i<nl;i++) ansv += addi[c[x][i]]; 90 printf("%I64d ",ansv); 91 } 92 } 93 else 94 { 95 scanf("%d",&y); 96 if(siz[x]>=SIZE) 97 { 98 add[x]+=(LL)y; //big->small 99 //big->big 100 } 101 else 102 { 103 int nl=g[x].size(); //small->big 104 for(int i=0;i<nl;i++) 105 ans[g[x][i].fir] += y*(LL)g[x][i].sec; 106 nl=c[x].size(); //small->small1 107 for(int i=0;i<nl;i++) addi[c[x][i]] += (LL)y; 108 } 109 } 110 } 111 } 112 return 0; 113 }