• HDU 4630 No Pain No Game 树状数组+离线查询


    思路参考 这里

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <cstdlib>
      4 #include <algorithm>
      5 
      6 using namespace std;
      7 
      8 const int MAXN = 50010;
      9 
     10 struct node
     11 {
     12     int l, r;
     13     int idx;
     14 };
     15 
     16 node Qry[MAXN];  //查询
     17 int C[MAXN];     //树状数组
     18 int vis[MAXN];   // i 的倍数上一次出现的位置
     19 int num[MAXN];   //原数组
     20 int ans[MAXN];   //答案
     21 int N, Q;
     22 
     23 bool cmp( node a, node b )
     24 {
     25     return a.l > b.l;
     26 }
     27 
     28 int lowbit( int x )
     29 {
     30     return x & (-x);
     31 }
     32 
     33 int query( int x )
     34 {
     35     int res = 0;
     36     while ( x > 0 )
     37     {
     38         res = max( res, C[x] );
     39         x -= lowbit(x);
     40     }
     41     return res;
     42 }
     43 
     44 void Add( int x, int val )
     45 {
     46     while ( x <= N )
     47     {
     48         C[x] = max( C[x], val );
     49         x += lowbit(x);
     50     }
     51     return;
     52 }
     53 
     54 int main()
     55 {
     56     int T;
     57     scanf( "%d", &T );
     58     while ( T-- )
     59     {
     60         scanf( "%d", &N );
     61         for ( int i = 1; i <= N; ++i )
     62             scanf( "%d", &num[i] );
     63 
     64         scanf( "%d", &Q );
     65         for ( int i = 0; i < Q; ++i )
     66         {
     67             scanf("%d%d", &Qry[i].l, &Qry[i].r );
     68             Qry[i].idx = i;
     69         }
     70 
     71         sort( Qry, Qry + Q, cmp );
     72         memset( C, 0, sizeof(C) );
     73         memset( vis, 0, sizeof(vis) );
     74 
     75         int i = 0, j = N;
     76         while ( i < Q )
     77         {
     78             while ( j > 0 && j >= Qry[i].l )
     79             {
     80                 for ( int k = 1; k*k <= num[j]; ++k )
     81                 {
     82                     if ( num[j] % k == 0 )
     83                     {
     84                         if ( vis[k] )
     85                         {
     86                             Add( vis[k], k );
     87                         }
     88                         vis[k] = j;
     89 
     90                         int tmp = num[j] / k;
     91                         if ( tmp != k )
     92                         {
     93                             if ( vis[tmp] )
     94                             {
     95                                 Add( vis[tmp], tmp );
     96                             }
     97                             vis[tmp] = j;
     98                         }
     99                     }
    100                 }
    101                 --j;
    102             }
    103 
    104             ans[ Qry[i].idx ] = query( Qry[i].r );
    105             ++i;
    106         }
    107 
    108         for ( int i = 0; i < Q; ++i )
    109         printf( "%d
    ", ans[i] );
    110     }
    111     return 0;
    112 }

    n个数,如果把n个数的约数全部写出来。查询[l,r]之间的gcd的最大值,就相当于找一个最大的数,使得这个数是[l,r]之间至少是两个的约数。

    对于一个数n,在sqrt(n)内可以找出所有约数。

    我的做法是对查询进行离线处理。

    将每个查询按照 l 从大到小排序。

    然后 i 从 n~0 ,表示从后面不断扫这些数。

    对于数a[i],找到a[i]的所有约数,对于约数x,在x上一次出现的位置加入值x.

    这样的查询的时候,只要查询前 r 个数的最大值就可以了。

  • 相关阅读:
    持续集成(转)
    Java中前台JSP请求Servlet实例(http+Servlet)
    Java中Map集合的四种访问方式(转)
    Python中字符串操作
    Python中的range函数用法
    Python学习资料下载地址(转)
    Linux性能工具介绍
    性能问题定位方法
    录制脚本前需要理解的几个基本概念
    Python 硬件底层基础理论
  • 原文地址:https://www.cnblogs.com/GBRgbr/p/3227816.html
Copyright © 2020-2023  润新知