hdu 4777 樹狀數組這麼用好厲害

題意:

給出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
*/

這個樣例完全沒有用..我使用它調代碼了


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章