HDU 4777 Rabbit Kingdom【树状数组】
2016-07-12 12:53
302 查看
题意:
给定序列,若干询问,求给定询问区间中互质的数的个数。分析:
智商太低理解了好久好久,最后还是看别人讲解和代码明白的。参考设l[i]为位置为i的元素左边第一个与w[i]不互质的数,r[i]为右边第一个与w[i]不互质的数,那么(l[i],r[i])区间内的所有数均与w[i]互质。
假设我们从头开始扫,为了防止重复计算,我们不管i左边的数,那么每遇到i,就把i的贡献加到后面相应的区间[i,r[i])里,实现起来我们就可以用树状数组(或线段树)维护区间互质数的对数和,每遇到i,就add(i,1),add(r[i],−1)。
下面处理询问,首先对所有询问根据区间左端点进行排序,然后我们从头开始扫,设头指针pp=1,每次遇到l[i]=pp时,说明对于左端点在pp之后的询问他是有贡献的,就把他的贡献加到相应的区间中,即[i,r[i]),指针扫过时再进行还原。我们可以用vector保存每个l[i]=pp的元素位置i,然后每次访问到一个位置直接遍历相应的vector即可。
代码:
#include<cstdio> #include<vector> #include<iostream> #include<algorithm> #include<cstring> using namespace std; const int maxn = 200000 + 5, oo = 0x3f3f3f3f; vector<int>prime[maxn]; vector<int>loc[maxn]; int l[maxn], r[maxn]; int w[maxn]; int pos[maxn]; int bit[maxn]; int ans[maxn]; bool isprime[maxn]; int n, q; struct Q{ int lq; int rq;int num; bool operator < (const Q &a) const{ return lq < a.lq; } }; Q query[maxn]; int h[maxn]; void initprime() { int tot = 0; memset(isprime, false, sizeof(isprime)); memset(h, 0, sizeof(h)); for(int i = 2; i < maxn; i++){ if(!isprime[i]){ h[tot++] = i; for(int j = 2 * i; j < maxn; j += i){ isprime[j] = true; } } } for(int i = 0; i < tot; i++){ for(int j = h[i]; j < maxn; j += h[i]){ prime[j].push_back(h[i]); } } } void add(int i, int x) { while(i <= n){ bit[i] += x; i += i & (-i); } } int sum(int i) { int ans = 0; while(i){ ans += bit[i]; i -= i & (-i); } return ans; } int main (void) { initprime(); while(scanf("%d%d", &n, &q) && (n + q)){ for(int i = 1; i <= maxn; i++){ loc[i].clear(); } for(int i = 1; i <= n; i++){ scanf("%d", &w[i]); } memset(pos, 0, sizeof(pos)); int a; for(int i = 1; i <= n; i++){ a = 0; for(int j = 0; j < prime[w[i]].size(); j++){ a = max(a, pos[prime[w[i]][j]]); pos[prime[w[i]][j]] = i; } l[i] = a; loc[a].push_back(i); } a = oo; memset(pos, 0x3f, sizeof(pos)); for(int i = n; i >= 1; i--){ a = oo; for(int j = 0; j < prime[w[i]].size(); j++){ a = min(a, pos[prime[w[i]][j]]); pos[prime[w[i]][j]] = i; } r[i] = a; } //for(int i = 1; i <= n; i++)cout<<i<<' '<<l[i]<<' '<<r[i]<<endl; int tl, tr; for(int i = 0; i < q; i++){ scanf("%d%d", &query[i].lq, &query[i].rq); query[i].num = i; } sort(query, query + q); memset(bit, 0, sizeof(bit)); for(int i = 1; i <= n; i++){ if(!l[i]){ add(i, 1); if(r[i] <= n) add(r[i], -1); } } int pp = 1; for(int i = 0; i < q; i++){ while(pp < query[i].lq){ add(pp, -1); if(r[pp] <= n) add(r[pp], 1); for(int j = 0; j < loc[pp].size(); j++){ add(loc[pp][j], 1); if(r[loc[pp][j]] <= n) add(r[loc[pp][j]], -1); } pp++; } ans[query[i].num] = sum(query[i].rq) - sum(query[i].lq - 1); } for(int i = 0; i < q; i++){ printf("%d\n", ans[i]); } } return 0; }
相关文章推荐
- nuget常用命令
- 最简单的基于FFMPEG的转码程序
- mac思维导图-时刻记录你的遐想
- Android架构实例分析之编写hello驱动的系统硬件服务
- 使用BeautifulSoup实现的图片爬虫
- performance_schema丢失
- 装饰器模式
- js 监控浏览器关闭事件
- js中使用正则表达式(g模式和非g模式的区别)
- POI操作Excel常用方法总结
- Leetcode 83. Remove Duplicates from Sorted List (Easy) (cpp)
- Weblogic修改控制台用户名和密码错误的解决方法
- Leetcode 203. Remove Linked List Elements (Easy) (cpp)
- 仓库库存周转率公式计算实例
- Servelet-页面乱码(非英文字符全部是问号)
- fragmentTransaction.replace无法全屏的问题
- registe关键字的注意事项
- [转载]Java数组扩容算法及Java对它的应用
- 为什么降雨还不凉快? —— 湿度
- C语言程序的存储区域