HDU 4777 Rabbit Kingdom(树状数组+离线预处理)

Problem Description
  Long long ago, there was an ancient rabbit kingdom in the forest. Every rabbit in this kingdom was not cute but totally pugnacious, so the kingdom was in chaos in season and out of season.
  n rabbits were numbered form 1 to n. All rabbits’ weight is an integer. For some unknown reason, two rabbits would fight each other if and only if their weight is NOT co-prime.
  Now the king had arranged the n rabbits in a line ordered by their numbers. The king planned to send some rabbits into prison. He wanted to know that, if he sent all rabbits between the i-th one and the j-th one(including the i-th one and the j-th one) into prison, how many rabbits in the prison would not fight with others.
  Please note that a rabbit would not fight with himself.

Input
  The input consists of several test cases.
  The first line of each test case contains two integer n, m, indicating the number of rabbits and the queries.
  The following line contains n integers, and the i-th integer Wi indicates the weight of the i-th rabbit.
  Then m lines follow. Each line represents a query. It contains two integers L and R, meaning the king wanted to ask about the situation that if he sent all rabbits from the L-th one to the R-th one into prison.
  (1 <= n, m, Wi <= 200000, 1 <= L <= R <= n)
  The input ends with n = 0 and m = 0.

Output
  For every query, output one line indicating the answer.

Sample Input
3 2
2 1 4
1 2
1 3
6 4
3 6 1 2 5 3
1 3
4 6
4 4
2 6
0 0

Sample Output
2
1
1
3
1
2
Hint
  In the second case, the answer of the 4-th query is 2, because only 1 and 5 is co-prime with other numbers in the interval [2,6] .

大致题意:给你一个长度为n的序列,有m次询问,每次查询一个区间,问这个区间里有多少个数和这个区间其他所有数互质

思路:参考dalao的博客http://blog.csdn.net/u011663071/article/details/39059483
弱鸡只能想到预处理出每个位置上的数字向左和向右最多能到达的位置,满足在这个区间内其他数与之互质,接下来怎么用树状数组去维护和查询就没思路了。。。。

代码如下

//#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=2e5+10;
vector <int> Divisor[maxn]; //保存数i的所有约数 
vector <int> vc[maxn];//记录那些左边第一个非互质的位置出现在i的数的位置有哪些 
int Tree[maxn];
int v[maxn]; 
int vl[maxn];
int vr[maxn];
int f[maxn];//记录约数i第一次出现的位置 
int ans[maxn];//记录第i次查询的答案 
int n,m;
struct node
{
    int l,r,id;
}q[maxn];
bool cmp(node a,node b)
{
    return a.lint lowbit(int x)
{
    return x&-x;
}
int sum(int x)
{
    int ans=0;
    while(x>0)
    {
        ans+=Tree[x];
        x-=lowbit(x);
    }
    return ans;
}
void add(int x,int date)
{
    while(x<=n)
    {
        Tree[x]+=date;
        x+=lowbit(x);
    }
    return ;
}

void pre()//预处理出每个数的左边第一个非互质的位置和右边第一个非互质的位置   
{
    for(int i=0;i<=n;i++)
        vc[i].clear();
    memset(f,0,sizeof(f));
    for (int i=1;i<=n;i++)  
        vl[i]=vr[i]=0; 
    for(int i=1;i<=n;i++)
    {
        for(int num=0;numint p=Divisor[v[i]][num];
            if(f[p]==0)
            {
                f[p]=i;
                continue;
            }
            int wei=f[p];
            if(vr[wei]==0)
                vr[wei]=i;
            if(vl[i]int main()
{
    for (int i=2;i<=200000;i++)  
        for (int t=i;t<=200000;t+=i)  
            Divisor[t].push_back(i); 

    while(scanf("%d%d",&n,&m)&&(n+m))
    {

        for(int i=1;i<=n;i++)
            scanf("%d",&v[i]);
        for(int i=1;i<=m;i++)
            scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;

        sort(q+1,q+n+1,cmp);//按查询区间左端点非递增排序 

        for (int i=1;i<=n;i++)  
            Tree[i]=0;   
        pre(); 
        int cnt=1;
        for(int i=0;i<=n;i++)
        {
            while(q[cnt].l==i)
            {
                ans[q[cnt].id]=sum(q[cnt].r)-sum(q[cnt].l-1);
                cnt++;    
            }    
            for(int num=0;num1);
                if(vr[vc[i][num]]!=0)
                add(vr[vc[i][num]],-1);
            }
            if(vr[i]!=0)
            add(vr[i],1);
        } 
        for(int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    }
}

你可能感兴趣的:(线段树&树状数组&主席树)