zoukankan      html  css  js  c++  java
  • hdu(预处理+线段树)

    给n个数,m个询问, 问任意区间内与其它数互质的数有多少个

    比如3个数1 2 4,询问[1,3] 那么答案是1

    千万要记住,这样的题目,如果你不转变下,使劲往线段树想(虽然转变之后,也说要用到线段树,但是维护的东西不同了),那么会发现这样的题目,区间与区间之间是无法传递信息的,

    区间与区间是无法传递信息的,区间与区间之间是无法传递信息的,重要的东西说三遍。

    设n个数,存在数组a[]里面

    我们预处理出,L[],和R[],L[i] 表示从i往左,第一个与a[i]不互质的数的位置+1,  R[i]表示从i往右,第一个与a[i]不互质的数的位置-1

    即L[i] 表示 [L[i],i]内的所有数都与a[i]互质,R[i]表示[i,R[i]]内的所有数都与a[i]互质 

     然后我们离线处理,将所有的询问按照左端点排序

    然后枚举左端点i,将所有L[j] = i的 [j,R[j]]区间+1,因为当左端点为i时,L[j]=i的数都在各自的有效区间[j,R[j]]里面生效了

    当i=询问的区间的左端点时,只要查询右端点被加了多少次就行了。

    走过i时,第i个数不再生效,所以将[i,R[i]]区间-1

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<string.h>
      4 #include<algorithm>
      5 #include <vector>
      6 using namespace std;
      7 const int N = 200000 + 10;
      8 vector<int> prime[N];
      9 vector<int> cL[N];
     10 int a[N],L[N],R[N];
     11 int mark[N];
     12 int tree[N<<2],lazy[N<<2];
     13 int ans[N];
     14 void pushDown(int rt)
     15 {
     16     if(lazy[rt])
     17     {
     18        lazy[rt<<1] += lazy[rt];
     19        lazy[rt<<1|1] += lazy[rt];
     20        tree[rt<<1] += lazy[rt];
     21        tree[rt<<1|1] += lazy[rt];
     22        lazy[rt] = 0;
     23     }
     24 }
     25 void update(int l, int r, int rt, int L, int R, int val)
     26 {
     27     if(L<=l && R>=r)
     28     {
     29         lazy[rt]+=val;
     30         tree[rt] += val;
     31         return;
     32     }
     33     pushDown(rt);
     34     int mid = (l+r)>>1;
     35     if(L<=mid)
     36         update(l,mid,rt<<1,L,R,val);
     37     if(R>mid)
     38         update(mid+1,r,rt<<1|1,L,R,val);
     39 
     40 }
     41 int  query(int l, int r, int rt, int pos)
     42 {
     43     if(l==r)
     44     {
     45         return tree[rt];
     46     }
     47     pushDown(rt);
     48     int mid = (l+r)>>1;
     49     if(pos<=mid)
     50         return query(l,mid,rt<<1,pos);
     51     else
     52         return query(mid+1,r,rt<<1|1,pos);
     53 }
     54 struct Node
     55 {
     56     int l,r,id;
     57     bool operator<(const Node&rhs)const
     58     {
     59         return l < rhs.l;
     60     }
     61 }q[N];
     62 
     63 void getPrime()
     64 {
     65     for(int i=2;i<=200000;++i)
     66     {
     67         if(!mark[i])
     68         for(int j=i;j<=200000;j+=i)
     69         {
     70             mark[j] = true;
     71             prime[j].push_back(i);//得到j的所有素数因子i
     72         }
     73     }
     74 }
     75 void init(int n)
     76 {
     77     memset(mark,0,sizeof(mark));
     78     for(int i=0; i<prime[a[1]].size(); ++i)
     79         mark[prime[a[1]][i]] = 1;
     80     L[1] = 1;
     81     cL[1].push_back(1);
     82     for(int i=2;i<=n;++i)
     83     {
     84         int pos = 0;
     85         for(int j=0; j<prime[a[i]].size(); ++j)
     86         {
     87             pos = max(pos,mark[prime[a[i]][j]]);
     88             mark[prime[a[i]][j]] = i;
     89         }
     90         L[i] = pos + 1;
     91         cL[L[i]].push_back(i);
     92     }
     93     for(int i=2;i<N;++i)mark[i] = n + 1;
     94     for(int i=0;i<prime[a[n]].size(); ++i)
     95         mark[prime[a[n]][i]] = n;
     96     R[n] = n;
     97     for(int i=n-1;i>=1;--i)
     98     {
     99         int pos = n + 1;
    100         for(int j=0;j<prime[a[i]].size(); ++j)
    101         {
    102              pos = min(pos,mark[prime[a[i]][j]]);
    103              mark[prime[a[i]][j]] = i;
    104         }
    105         R[i] = pos - 1;
    106     }
    107 }
    108 int main()
    109 {
    110     int n,m;
    111     getPrime();
    112     while(scanf("%d%d",&n,&m),n+m)
    113     {
    114         memset(tree,0,sizeof(tree));
    115         memset(lazy,0,sizeof(lazy));
    116         for(int i=1;i<=n;++i)
    117         {
    118             scanf("%d",&a[i]);
    119             cL[i].clear();
    120         }
    121         init(n);
    122         for(int i=0;i<m;++i)
    123         {
    124             scanf("%d%d",&q[i].l,&q[i].r);
    125             q[i].id = i;
    126         }
    127         sort(q,q+m);
    128         int cur  = 0;
    129         //枚举左端点
    130         for(int i=1;i<=n;++i)
    131         {
    132             //当左端点为i时,使得所有L[j] = i的数都在各自的区间[j,R[j]]
    133             //所以在[j,R[j]]区间+1
    134             for(int j=0;j<cL[i].size(); ++j)
    135                 update(1,n,1,cL[i][j],R[cL[i][j]],1);
    136             //当询问的左端点为i时,
    137             while(q[cur].l==i)
    138             {
    139                 //只要询问右端点的值就行了,因为每个数都在自己能生效的区间里面+1了
    140                 ans[q[cur].id] = query(1,n,1,q[cur].r);
    141                 cur++;
    142             }
    143             //要走过第i个数了,所以第i个数不再生效了,所以将[i,R[i]]区间-1
    144             update(1,n,1,i,R[i],-1);
    145         }
    146         for(int i=0;i<m;++i)
    147             printf("%d
    ",ans[i]);
    148     }
    149     return 0;
    150 }
  • 相关阅读:
    MP教程-入门
    [15213] Assembly
    Crack the code interview
    [interview questions] 资料总结
    [Two Sigma OA] Longest Chain
    [Tow Sigma OA] friend cycles
    [security]
    [security] GNUpg
    [coursera] 面试前准备
    [coursera] [design] Hangman
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4886191.html
Copyright © 2011-2022 走看看