【分块+树状数组】codechef November Challenge 2014 .Chef and Churu

https://www.codechef.com/problems/FNCS

【题意】

【思路】

  • 把n个函数分成√n块,预处理出每块中各个点(n个)被块中函数(√n个)覆盖的次数
  • 查询时求前缀和,对于整块的分块求和,剩下右边不构成完整的一个块的树状数组求和
  • 预处理:计算每个块中,序列中的第i个点被块中函数覆盖的次数,求出每个块内前缀的和(O(n√n));对于每个点,更新树状数组(nlogn)
  • 单点修改:对于块状数组,因为已经知道了每个点被覆盖的次数,所以维护很简单(O(√n));对于树状数组,直接单点更新(O(logn));然后把a[pos]本身的值更新为x
  • 查询:计算前缀和,求x到y之间的函数和就是计算cal(y)-cal(x-1)。对于前缀和,对于整块的直接求和(O(√n)),对于最右边剩下的树状数组查询区间和(最多√n个函数,每个函数logn,所以复杂度为√nlogn)
  • 综上,时间复杂度为O(n√nlogn)
  • 注意要爆long long,1e5*1e5*1e9=1e19,long long 的最大值为9223372036854775807,9e18多一点

【Accepted】

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<string>
  5 #include<cmath>
  6 #include<algorithm> 
  7 
  8 using namespace std;
  9 typedef unsigned long long ull;
 10 const int maxn=1e5+2;
 11 int n,m;
 12 int a[maxn];
 13 int belong[maxn];
 14 int l[400];
 15 int r[400];
 16 ull sum[maxn];
 17 ull tree[maxn];
 18 int vis[400][maxn];
 19 struct Node
 20 {
 21     int l;
 22     int r;
 23 }q[maxn];
 24 
 25 void init()
 26 {
 27     for(int i=1;i<=n;i++)
 28     {
 29         tree[i]=0ull;    
 30     }    
 31 }
 32 
 33 int lowbit(int x)
 34 {
 35     return x&(-x);
 36 }
 37 void add(int k,int x)
 38 {
 39     while(k<=n)
 40     {
 41         tree[k]+=1ull*x;
 42         k+=lowbit(k);
 43     }
 44 }
 45 
 46 ull query(int k)
 47 {
 48     ull res=0ull;
 49     while(k)
 50     {
 51         res+=tree[k];
 52         k-=lowbit(k);
 53     }
 54     return res;
 55  } 
 56 ull query(int l,int r)
 57 {
 58     return query(r)-query(l-1);
 59  } 
 60 ull cal(int x)
 61 {
 62     if(x<1)
 63     {
 64         return 0;
 65     }
 66     int b=belong[x];
 67     ull res=0ull;
 68     for(int i=1;i<b;i++)
 69     {
 70         res+=sum[i];
 71     }
 72     for(int i=l[b];i<=x;i++)
 73     {
 74         res+=query(q[i].l,q[i].r);
 75     }
 76     return res;
 77 }
 78 ull cal(int x,int y)
 79 {
 80     return cal(y)-cal(x-1);
 81 }
 82 int main()
 83 {
 84         scanf("%d",&n);
 85         init();
 86         for(int i=1;i<=n;i++)
 87         {
 88             scanf("%d",&a[i]);                        
 89             add(i,a[i]);
 90         }
 91         int block=sqrt(n);
 92         for(int i=1;i<=n;i++)
 93         {
 94             scanf("%d%d",&q[i].l,&q[i].r);    
 95             belong[i]=(i-1)/block+1;
 96         }    
 97         int cnt=n/block;
 98         if(n%block)
 99         {
100             cnt++;
101         }
102         for(int i=1;i<=cnt;i++)
103         {
104             l[i]=(i-1)*block+1;
105             r[i]=i*block;
106         }    
107         r[cnt]=n;
108         for(int i=1;i<=cnt;i++)
109         {
110             for(int k=l[i];k<=r[i];k++)
111             {
112                 vis[i][q[k].l]++;
113                 vis[i][q[k].r+1]--;
114             }
115             for(int k=1;k<=n;k++)
116             {
117                 vis[i][k]+=vis[i][k-1];
118                 sum[i]+=1ull*vis[i][k]*a[k];
119             }
120         } 
121         scanf("%d",&m);
122         while(m--)
123         {
124             int op;
125             scanf("%d",&op);
126             if(op==1)
127             {
128                 int pos,x;
129                 scanf("%d%d",&pos,&x);
130                 for(int i=1;i<=cnt;i++)
131                 {
132                     sum[i]+=1ull*vis[i][pos]*(x-a[pos]); 
133                 }
134                 add(pos,x-a[pos]);
135                 a[pos]=x;
136             }
137             else
138             {
139                 int x,y;
140                 scanf("%d%d",&x,&y);
141                 ull ans=cal(x,y); 
142                 printf("%llu\n",ans);
143             }
144         }
145     
146     return 0;
147 }
分块+树状数组

 

posted @ 2017-07-19 12:48  shulin15  阅读(187)  评论(0编辑  收藏  举报