HDU-5869 樹狀數組+離線+預處理

思路講的很詳細的博客

預處理求區間[l,r]的gcd,固定r向左
如[1,3]->[3,3]->[2,3]->[1,2,3]這樣才保證了求出了所有的區間內所有的gcd

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.Arrays;


public class Main_HDU5869 {
	static ArrayList<node5869_>[] gcd = new ArrayList[100005]; 
	static int n,q;
	static int[] ans = new int[100005];
	static int[] a = new int[100005];
	static node5869[] node = new node5869[100005];
	static int[] vis = new int[1000005];
	static int[] sum = new int[1000005];
	public static void main(String[] args) throws IOException {
		StreamTokenizer sc = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		PrintWriter out = new PrintWriter(System.out);
		for(int i=0;i<=100000;i++) {
			gcd[i] = new ArrayList<node5869_>();
		}	
		while(sc.nextToken()!=StreamTokenizer.TT_EOF) {
			n = (int)sc.nval;
			sc.nextToken();
			q = (int)sc.nval;

			for(int i=1;i<=n;i++) {
				sc.nextToken();
				a[i] = (int)sc.nval;
				gcd[i].clear();
			}
			for(int i=1,j;i<=n;i++) {	  //預處理求區間gcd  固定r向左求出每個區間的gcd種類  如求[1,3]->[3,3]->[2,3]->[1,2,3]     
				int t = a[i];
				int len = gcd[i-1].size();
				gcd[i].add(new node5869_(i,a[i]));	//gcd[i] 表示以i結尾的每個區間gcd   		
				for(j=0;j<len;j++) {
					int tgcd = gcd(t,gcd[i-1].get(j).gcd);
					int pos = gcd[i-1].get(j).i;   
					if(tgcd!=t) {  //去掉所求區間重複的gcd
						gcd[i].add(new node5869_(pos,tgcd));
						t = tgcd;
					}
				}	
			}
			for(int i=1;i<=q;i++) {
				sc.nextToken();
				int l = (int)sc.nval;
				sc.nextToken();
				int r = (int)sc.nval;
				node[i] = new node5869(l,r,i);
			}
			Arrays.sort(node,1,1+q);
			Arrays.fill(vis, 0);
			Arrays.fill(ans, 0);
			Arrays.fill(sum, 0);
			int k = 1;
			for(int i=1;i<=n;i++) {
				int len = gcd[i].size();
				for(int j=0;j<len;j++) {
					if(vis[gcd[i].get(j).gcd]!=0) {  //說明該gcd前面出現過    vis存放的是該gcd上一次出現的位置
						update(vis[gcd[i].get(j).gcd],-1);
					}
					vis[gcd[i].get(j).gcd] = gcd[i].get(j).i;
					update(gcd[i].get(j).i,1);
				}
				while(k<=q&&node[k].r<=i) {
					ans[node[k].id] = getsum(node[k].r)-getsum(node[k].l-1);
					k++;
				}				
			}
			for(int i=1;i<=q;i++) {
				out.println(ans[i]);
			}
			out.flush();
		}
	}
	public static int gcd(int a,int b) {
		if(b==0) return a;
		else return gcd(b,a%b);
	}
	public static void update(int x,int d) {
		for(int i=x;i<=n;i+=i&(-i)) {
			sum[i] += d;
		}
	}
	public static int getsum(int x) {
		int ans = 0;
		for(int i=x;i>=1;i-=i&(-i)) {
			ans += sum[i];
		}
		return ans;
	}
}
class node5869 implements Comparable<node5869>{
	int l,r,id;
	public node5869(int l,int r,int id) {
		this.l = l;
		this.r = r;
		this.id = id;
	}
	@Override
	public int compareTo(node5869 o) {
		return this.r-o.r;
	}
}
class node5869_{
	int i,gcd;
	public node5869_(int i,int gcd) {
		this.i = i;
		this.gcd = gcd;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章