HDU--5286(分块,*)

2015-07-20 14:25:46

传送门

题意:给出最多50000个数,50000个询问,每个询问是统计区间【l,r】区间内每个数的出现次数,然后累加 ci^bi (表示 ci 这个数出现了 bi 次),强制在线。

思路:分块可以做,但是关键在于怎么处理涉及答案合并的询问。

  一开始没什么思路,但是看了官方题解才知道只要预先统计出(1)cnt[i][j],表示数 i 在前 j 块内出现过多少次。(2)g[i][j],表示从块 i 头部到块 j 尾部这个区间的答案。

  处理 cnt 和 g 数组的复杂度都是 n*sqrt(n)。对于询问,考虑最复杂的情况,区间的两边均有不完整的块a和b,中间有若干个整块a+1~b-1,首先获得中间整块的答案 g[a+1][b-1],然后暴力扫描不完整块a和b,统计这些不完整块中的数在 a+1~b-1 完整块中的出现次数(通过 cnt 数组来计算),然后再暴力扫描一边这些数,更新答案即可。

  总结:精髓在于 g 数组和 cnt 数组的配合使用。

 

(打的比较长,效率还可以,1216MS)

  1 #include <cstdio>
  2 #include <ctime>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <cmath>
  6 #include <vector>
  7 #include <map>
  8 #include <set>
  9 #include <stack>
 10 #include <queue>
 11 #include <string>
 12 #include <iostream>
 13 #include <algorithm>
 14 using namespace std;
 15 
 16 #define getmid(l,r) ((l) + ((r) - (l)) / 2)
 17 #define MP(a,b) make_pair(a,b)
 18 #define PB push_back
 19 
 20 typedef long long ll;
 21 typedef pair<int,int> pii;
 22 const double eps = 1e-8;
 23 const int INF = (1 << 30) - 1;
 24 const int MAXN = 50010;
 25 const int MAX_SQR = 240;
 26 const ll mod = 1e9 + 7;
 27 
 28 int T,n,q,block,bcnt;
 29 int A[MAXN],B[MAXN],C[MAXN],Bid[MAXN];
 30 int L[MAX_SQR],R[MAX_SQR];
 31 int Cnt[MAXN][MAX_SQR];
 32 int num[MAXN],sz;
 33 ll G[MAX_SQR][MAX_SQR];
 34 
 35 vector<ll> pw[MAXN];
 36 
 37 void Pre(){
 38     //pre-cal power
 39     for(int i = 1; i <= sz; ++i) pw[i].clear(); //清空幂向量
 40     for(int i = 1; i <= n; ++i) if(pw[A[i]].size() == 0){ //处理过的不用重复处理
 41         pw[A[i]].push_back(0);
 42         pw[A[i]].push_back(C[i]);
 43         for(int j = 2; j <= num[A[i]]; ++j){
 44             pw[A[i]].push_back(pw[A[i]][j - 1] * C[i] % mod);
 45         }
 46     }
 47     //Cal Cnt array
 48     memset(Cnt,0,sizeof(Cnt));
 49     for(int i = 1; i <= n; ++i){
 50         Cnt[A[i]][Bid[i]]++;
 51     }
 52     for(int i = 1; i <= sz; ++i){
 53         for(int j = 2; j <= bcnt; ++j){
 54             Cnt[i][j] += Cnt[i][j - 1]; //数i在前j块内的出现次数
 55         }
 56     }
 57     //Cal g array
 58     for(int i = 1; i <= bcnt; ++i){
 59         memset(num,0,sizeof(num));
 60         ll sum = 0;
 61         for(int j = i; j <= bcnt; ++j){
 62             for(int k = L[j]; k <= R[j]; ++k){
 63                 sum -= pw[A[k]][num[A[k]]++];
 64                 sum += pw[A[k]][num[A[k]]];
 65             }
 66             G[i][j] = sum % mod;
 67         }
 68     }
 69 }
 70 
 71 int Query(int l,int r){
 72     //solve left
 73     int lid = Bid[l],rid = Bid[r];
 74     int m_lid = l > L[lid] ? lid + 1 : lid;
 75     int m_rid = r < R[rid] ? rid - 1 : rid;
 76     if(m_lid > m_rid){ //不存在中间块,直接暴力
 77         memset(num,0,sizeof(num));
 78         ll res = 0;
 79         for(int i = l; i <= r; ++i){
 80             res -= pw[A[i]][num[A[i]]++];
 81             res += pw[A[i]][num[A[i]]];
 82         }
 83         return (res % mod + mod) % mod;
 84     }
 85     ll res = G[m_lid][m_rid];
 86     //pre-cal num array
 87     if(l > L[lid]){
 88         for(int i = l; i <= R[lid]; ++i){
 89             num[A[i]] = Cnt[A[i]][m_rid] - Cnt[A[i]][m_lid - 1];
 90         }
 91     }
 92     if(r < R[rid]){
 93         for(int i = L[rid]; i <= r; ++i){
 94             num[A[i]] = Cnt[A[i]][m_rid] - Cnt[A[i]][m_lid - 1];
 95         }
 96     }
 97     //bf-cal non block A[i]
 98     if(l > L[lid]){
 99         for(int i = l; i <= R[lid]; ++i){
100             res -= pw[A[i]][num[A[i]]++];
101             res += pw[A[i]][num[A[i]]];
102         }
103     }
104     if(r < R[rid]){
105         for(int i = L[rid]; i <= r; ++i){
106             res -= pw[A[i]][num[A[i]]++];
107             res += pw[A[i]][num[A[i]]];
108         }
109     }
110     return (res % mod + mod) % mod;
111 }
112 
113 int main(){
114     int a,b,l,r;
115     scanf("%d",&T);
116     block = 400;
117     while(T--){
118         scanf("%d%d",&n,&q);
119         for(int i = 1; i <= n; ++i){
120             scanf("%d",A + i);
121             B[i] = C[i] = A[i]; //A是C的马甲,C是真身数据
122             Bid[i] = (i - 1) / block + 1;
123         }
124         bcnt = (n - 1) / block + 1;
125         for(int i = 1; i <= bcnt; ++i){
126             L[i] = (i - 1) * block + 1;
127             R[i] = min(n,i * block);
128         }
129         sort(B + 1,B + n + 1);
130         sz = unique(B + 1,B + n + 1) - B - 1; //unique 返回尾元素后面的地址
131         memset(num,0,sizeof(num));
132         for(int i = 1; i <= n; ++i){
133             A[i] = lower_bound(B + 1,B + sz + 1,A[i]) - B;
134             num[A[i]]++; //记录马甲数的数量
135         }
136         Pre();
137         int pre_ans = 0;
138         for(int o = 1; o <= q; ++o){
139             scanf("%d%d",&a,&b);
140             l = (a ^ pre_ans) % n + 1;
141             r = (b ^ pre_ans) % n + 1;
142             if(l > r){
143                 int tmp = l;
144                 l = r;
145                 r = tmp;
146             }
147             pre_ans = Query(l,r);
148             printf("%d\n",pre_ans);
149         }
150     }
151     return 0;
152 }

 

posted @ 2015-07-20 14:44  Naturain  阅读(147)  评论(0编辑  收藏  举报