Subset Sums

题意:

给一长度为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\n",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\n",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 }
View Code

 

posted @ 2017-03-05 00:19  lawyer'  阅读(115)  评论(0编辑  收藏  举报