码迷,mamicode.com
首页 > 编程语言 > 详细

hdu 4777 树状数组这么用好厉害

时间:2015-05-16 16:36:59      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:hdu

题意:

给出m个区间查询,查询 区间里和区间中的其他数字 都互质 的数字的个数

思路:

简单题,因为并没有 修改,全是查询

把所有查询读入,按照左端点 从左往右来处理。(原因稍后

首先预处理对于每一个位置(id)的数字,往左和往右最远到哪个位置,会出现和这个数字不互质的数字,用l[id]和r[id]保存下来。同时用邻接表(因为这么处理比较简单)保存下来对于一个位置iid,有哪个数字,它的“不互质区间”左端点是iid。——其实我感觉这个预处理过程,用到了素数打表,整数质分界,和我以前不知道的处理方法,比主算法还要难...sigh

然后就是用树状数组处理了。我们从数组最左端开始,每处理到一个位置id,这个位置右边的所有数字,就不用再考虑当前这个数字的影响了。所以我们就可以把所有L[x]=id的位置x 的count + 1,然后R[x]的count - 1。 同时我们应该把R[id]的count+1(因为我们之前给x的count+1的时候,曾经把R[x]的count减成了-1)

我也知道我写的不好理解...但是就是很明确却不大容易想到...:)

你来想,对于按照左端点从小到大排完序的所有区间,每次处理到区间左端点左边的那个位置时,当前区间和就是答案!真是好~

code:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#include<cstdlib>
using namespace std;

#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))
#define mod 1000000007
typedef pair<int,int> pii;
typedef long long LL;
//------------------------------
const int maxn = 200005;

struct node{
    int s, e, id;
    bool operator < (const node nt) const{
        if(s != nt.s)
            return s < nt.s;
        else return e < nt.e;
    }
}q[maxn];
int n, m;
int a[maxn];

struct BIT{
    int C[maxn];
    void init(){
        memset(C, 0, sizeof(C));
    }
    int lowbit(int x){
        return -x&x;
    }
    int sum(int x){
        int ret = 0;
        while(x > 0){
            ret += C[x];
            x -= lowbit(x);
        }
        return ret;
    }
    void add(int x,int v){
        while(x <= n){///这个地方的n是要根据C[]数组需要保存的范围来确定的,不一定就是n
            C[x] += v;
            x += lowbit(x);
        }
    }
}bit;



int vis[maxn], prime[maxn], pcnt = 0;
void getprime(){
    memset(vis, 0, sizeof(vis));
    for(long long i = 2; i < maxn; i++){
        if(!vis[i]){
            prime[pcnt++] = i;
            for(long long j = i*i; j < maxn; j+=i){
                vis[j] = 1;
            }
        }
    }
}
vector<int> g[maxn];
void getfac(int id){
    g[id].clear();
    int tmp;
    scanf("%d",&tmp);
    for(int i = 0; i < pcnt && prime[i] * prime[i] <= tmp; i++){
        if(tmp % prime[i] == 0){
            g[id].push_back(prime[i]);
            while(tmp % prime[i] == 0)
                tmp /= prime[i];
        }
    }
    if(tmp != 1) g[id].push_back(tmp);
}

int l[maxn], r[maxn], pos[maxn];//pos中存的是每个素因子出现的最靠右(左)的位置

vector<int> vec[maxn];
void deal(){
    memset(pos, 0, sizeof(pos));
    for(int i = 0; i < maxn; i++) vec[i].clear();
    for(int i = 1; i <= n; i++){
        getfac(i);
        l[i] = 1;
        for(int j = 0; j < g[i].size(); j++){
            int tmp = g[i][j];
            l[i] = max(l[i], pos[tmp]+1);//这个地方求出的其实是最左端的互质的位置
            pos[tmp] = i;
        }
        l[i]--;//所以这里位置往左移一个
        vec[l[i]].push_back(i);
    }

    memset(pos, INF, sizeof(pos));
    for(int i = n; i >= 1; i--){
        r[i] = n;
        for(int j = 0; j < g[i].size(); j++){
            int tmp = g[i][j];
            r[i] = min(r[i], pos[tmp]-1);
            pos[tmp] = i;
        }
        r[i]++;
    }
}
void init(){
    deal();
    int s, e;
    for(int i = 0; i < m; i++){
        scanf("%d%d",&s,&e);
        q[i].id = i;
        q[i].s = s;
        q[i].e = e;
    }
}
int ans[maxn];
void solve(){
    sort(q, q+m);
    int left = 1;

//    for(int i = 1; i <= n; i++){
//        printf("left = %d right = %d\n",l[i],r[i]);
//    }
//    for(int i = 1; i <= n; i ++){
//        printf("=== %d : \n",i);
//        for(int j = 0; j < vec[i].size(); j++){
//            printf("%d ",vec[i][j]);
//        }
//        if(vec[i].size() != 0)
//            printf("\n");
//    }

    bit.init();
    for(int i = 1; i <= n; i++){
        if(l[i] < 1){
            bit.add(i,1);
            if (r[i] <= n)
                bit.add(r[i], -1);
        }
    }
    for(int i = 0; i < m; i++){
        while(left < q[i].s){
//            bit.add(left, -1);//这个地方加不加无所谓,因为以后再也用不到left位置的值了
            if (r[left] <= n) bit.add(r[left], 1);
            for(int j = 0; j < vec[left].size(); j++){
                int k = vec[left][j];
                bit.add(k, 1);
                if (r[k] <= n)  bit.add(r[k], -1);
            }
            left++;
        }
        ans[q[i].id] = bit.sum(q[i].e) - bit.sum(q[i].s-1);
    }
    for(int i = 0; i < m; i++){
        printf("%d\n",ans[i]);
    }
}
int main(){
    getprime();
    while(scanf("%d%d",&n,&m) != EOF){
        init();
        solve();
    }
    return 0;
}
/*
10 2
2 3 4 5 6 7 8 9 10 11
*/

这个样例完全没有用..我使用它调代码了


hdu 4777 树状数组这么用好厉害

标签:hdu

原文地址:http://blog.csdn.net/u013382399/article/details/45768285

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!