ZOJ3800 GCD+离线线段树
来源:互联网 发布:淘宝海报在线制作 编辑:程序博客网 时间:2024/06/16 03:42
You are given a sequence {A0, A1, ..., AN-1} and an integer set called GS. Defined a function called G(L, R) on A, where G(L, R) = GCD(Ai) (L ≤ i< R) that is the greatest common divisor of all the integers in the subsequence {AL, AL+1, ..., AR-1}.
Now There're several questions for you. Give you three integers L, R and g, where g is an integer in GS. You need to calculate how many integer pairs (l, r) satisfy the condition that G(l, r) = g and L ≤ l < r ≤ R.
Input
Input will consist of multiple test cases. The first line of each case contains three integers N, M, Q (1≤ N, Q≤ 100000, 1 ≤ M ≤ 50), separated by spaces. The second line contains N integers, A0, A1, ..., AN-1 (1≤ Ai≤ 100000). The third line contains M integers, indicating the set GS. Every integer in GS is positive and less than 2000. For the next Q line, each line contains three integers, L, R, g (0≤ L< R≤ N, g∈ GS).
Output
For each case, output Q lines. Each line contains an integer, indicating the answer for the query.
Sample Input
4 4 41 2 3 41 2 3 40 4 10 4 20 4 30 4 4
Sample Output
7111
Author: LIN, Xi
Source: ZOJ Monthly, August 2014
题目大意:给你N个数,和一个大小为M的集合,有Q组询问,每一组都询问[L,R-1]的区间的子区间GCD值为g的有多少个,g是集合中的一个数。
解题思路:
首先,注意到M只有50,可以预处理。
然后,GCD对于区间有非增的性质,那么对于数组A中的一个数Ai,以i为左端点的子区间GCD=g的是有范围的,我们可以维护这个区间,不妨设为[L,R],
L作为第一个使得区间[i,L]的GCD为g的下标,即min{x|GCD(i,x)==g}
R作为最右边是g的倍数的下标的后一位,即max{x|A[x]%g==0}
那么范围只有以下几种情况:
1. Ai%g!=0 范围不存在
2. Ai%g==0 L不存在,R存在
3. Ai%g==0 L,R都存在
通过区间GCD删除一个数后不会小于原来的值,我们可以发现L,R具有单调性
那么可以用扫描线处理出以每个点为左端点,GCD为M中的一个数的符合的范围
有了这个下面就简单多了。
离线排序,通过M把询问分类,对于每一类按询问区间的右端点排序,把大于右端点的点的范围全部插入线段数,然后询问区间左端点即可
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>#define maxn 100010#define max(a,b) (a>=b ? a:b)#define ll long longusing namespace std;int n,m,q;int v[maxn],s[maxn],f[maxn],LL[55][maxn],RR[55][maxn];ll cc[55][maxn],ans[maxn];struct Query{ int l,r,g,x; friend bool operator<(Query a,Query b){ if(a.g!=b.g) return a.g<b.g; return a.l>b.l; }}Q[maxn];int Log[maxn];void init(){ for(int i=1;i<maxn;i++) Log[i]=log(i*1.0)/log(2.0);}void read(){ for(int i=1;i<=n;i++) scanf("%d",&v[i]); for(int i=1;i<=m;i++) scanf("%d",&s[i]); sort(s+1,s+m+1); for(int i=1;i<=m;i++) f[s[i]]=i; for(int i=1;i<=q;i++) scanf("%d%d%d",&Q[i].l,&Q[i].r,&Q[i].g),Q[i].x=i;}int dp[maxn][20];void RMQ(){ memset(dp,0,sizeof dp); for(int i=1;i<=n;i++) dp[i][0]=v[i]; for(int i=1;i<20;i++){ for(int j=1;j+(1<<i>>1)<=n;j++){ dp[j][i]=__gcd(dp[j][i-1],dp[j+(1<<i>>1)][i-1]); } }}int query_RMQ(int l,int r){ int h=Log[r-l+1]; return __gcd(dp[l][h],dp[r-(1<<h)+1][h]);}struct tree{ int l,r; ll s,lz;}a[maxn<<2];void build(int l,int r,int k){ a[k].l=l,a[k].r=r,a[k].s=0,a[k].lz=0; if(l<r){ int mid=(l+r)>>1; build(l,mid,k<<1); build(mid+1,r,k<<1|1); }}void pushdown(int k){ if(a[k].lz){ a[k<<1].s+=(a[k<<1].r-a[k<<1].l+1)*a[k].lz; a[k<<1|1].s+=(a[k<<1|1].r-a[k<<1|1].l+1)*a[k].lz; a[k<<1].lz+=a[k].lz; a[k<<1|1].lz+=a[k].lz; a[k].lz=0; }}void insert(int l,int r,int k){ if(l<=a[k].l&&a[k].r<=r){ a[k].s+=(r-l+1); a[k].lz++; }else{ pushdown(k); int mid=(a[k].l+a[k].r)>>1; if(r<=mid) insert(l,r,k<<1); else if(l>mid) insert(l,r,k<<1|1); else insert(l,mid,k<<1),insert(mid+1,r,k<<1|1); a[k].s=a[k<<1].s+a[k<<1|1].s; }}ll query(int l,int r,int k){ if(l<=a[k].l&&a[k].r<=r){ return a[k].s; }else{ pushdown(k); int mid=(a[k].l+a[k].r)>>1; if(r<=mid) return query(l,r,k<<1); else if(l>mid) return query(l,r,k<<1|1); else return query(l,mid,k<<1)+query(mid+1,r,k<<1|1); }}void solve(){ RMQ(); memset(cc,0,sizeof cc); for(int i=1;i<=m;i++){ int L=1,R=1; for(int j=1;j<=n;j++){ L=max(L,j),R=max(R,j); int GCD; if(v[j]%s[i]==0){ GCD=query_RMQ(j,L); if(GCD!=s[i]){ while(L<=n&&__gcd(GCD,v[L])!=s[i]&&GCD!=1) GCD=__gcd(GCD,v[L++]); } while(R<=n&&v[R]%s[i]==0) R++; } LL[i][j]=L,RR[i][j]=R; if(GCD!=s[i]) L=1; } } /*for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ cout<<i<<" "<<j<<" "<<LL[i][j]<<" "<<RR[i][j]<<endl; } }*/ sort(Q+1,Q+q+1); for(int i=1,j;i<=q;i++){ if(Q[i].g!=Q[i-1].g) build(1,n,1),j=n; int z=f[Q[i].g]; Q[i].l++; while(j>=Q[i].l){ if(RR[z][j]>LL[z][j]) insert(LL[z][j],RR[z][j]-1,1); j--; } ans[Q[i].x]=query(Q[i].l,Q[i].r,1); } for(int i=1;i<=q;i++){ printf("%lld\n",ans[i]); }}int main(){ //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); init(); while(~scanf("%d%d%d",&n,&m,&q)){ read(); solve(); } return 0;}
- ZOJ3800 GCD+离线线段树
- zoj3800线段树+离线
- gcd(线段树离线处理)——HDU 4630
- HDU 5381 The sum of gcd 离线处理+线段树
- HDU5869 Different GCD Subarray Query(线段树&&离线处理)
- HDU5869 Different GCD Subarray Query(离线线段树)
- [HDU 5869] Different GCD Subarray Query (线段树GCD+离线算法) (好题)
- HDU5869 Different GCD Subarray Query(线段树&&离线处理) 2016大连网络赛
- hdu5930 GCD线段树
- hdu 5381 The sum of gcd (线段树x树状数组x区间和维护进阶x离线处理)
- hdu5726 GCD (线段树+区间gcd)
- hdu4638(离线算法+线段树)
- hdu3874(离线思想+线段树)
- zoj 3724 离线+线段树
- HDU 4417 离线线段树
- HDU 3333 离线线段树
- POJ 2761 离线线段树
- 线段树离线处理专题
- 设置UIView能否被点击
- 程序员生存定律-六个程序员的故事(1)
- 少侠请小心介绍
- ExtJs事件处理
- n节点组成二叉树的个数
- ZOJ3800 GCD+离线线段树
- hdu 4777 Rabbit Kingdom (离线树状数组)
- Android Touch事件分发过程
- 【小猿說】国内移动互联网现状令人欣慰
- echarts学习笔记(4) ---- 如何使用 formatter 和 grid 这两把利器
- python 解释器
- grub 硬盘安装系统
- JAVA编程思想(4) - 多态(三)
- 转载!!!Hibernate插入和修改数据到数据库中时不修改存在默认值字段