牛客網暑期ACM多校訓練營(第一場)J-Different Integers [樹狀數組/莫隊]

                                           J-Different Integers

題意很清楚啦,就是找兩邊區間不同數字的個數,還是自己菜啦,我一眼瞅上去感覺是莫隊,主要原因是我昨天剛剛學習了qsc的莫隊算法視頻,以爲只有查詢操作,沒有修改操作,用莫隊就好啦,沒想到T到懷疑人生,最後可能是服務器的問題吧,我莫隊調整了常數,卡過去啦,不管咋說,還是要把代碼貼一下,紀念自己第一個莫隊算法題目(雖然還是T啦),謝謝叉姐。

代碼(莫隊):

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e5+7;

struct node {
    ll l, r, id;
} Q[maxn];

ll n, m, k, q;
int pos[maxn];
ll a[maxn], ans[maxn], ANS = 0, cnt = 0;
int mp[maxn];

bool cmp(node a, node b)
{
    if(pos[a.l] == pos[b.l]) return a.r < b.r;
    else return pos[a.l] < pos[b.l];
}

int L = 1, R = 0;

ll rd(){
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

void adds(int x)
{
    if(mp[a[x]] == 0) {
        ANS++;
    }
    mp[a[x]]++;
}

void del(int x)
{
    mp[a[x]]--;
    if(mp[a[x]] == 0) {
        ANS--;
    }
}

int main()
{
    while(~scanf("%lld%lld", &n, &q))
    {
        cnt = 0;
        memset(mp, 0, sizeof(mp));
        int sz = sqrt(maxn);                      //改改就過了
        for(int i = 1; i <= n; i++)
        {
            a[i] = rd();
            if(mp[a[i]] == 0) {
                mp[a[i]]++;
                cnt++;
            }
            else mp[a[i]]++;
            pos[i] = i/sz;
        }
        int cas = 0;
        for(int i = 1; i <= q; i++)
        {
            ll l, r;
            l = rd();
            r = rd();
            if(l >= (r - 1)) {
                ans[i] = cnt;
            } else {
                Q[cas].l = l;
                Q[cas].r = r;
                Q[cas++].id = i;
            }
        }

        sort(Q, Q+cas, cmp);
        ANS = cnt;
        L = Q[0].l;
        R = Q[0].l+1;
        //for(int i = L + 1; i < R; i++) del(i); ans[Q[0].id] = ANS;

        for(int i = 0; i < cas; i++)
        {
            while(L < Q[i].l)
            {
                L++;
                adds(L);
            }

            while(L > Q[i].l)
            {
                del(L);
                L--;
            }

            while(R < Q[i].r)
            {
                del(R);
                R++;
            }
            while(R > Q[i].r)
            {
                R--;
                adds(R);
            }
            ans[Q[i].id] = ANS;
        }
        //cout << "1" << endl;
        for(int i = 1; i <= q; i++) printf("%lld\n", ans[i]);
    }
    return 0;
}

題解是說用樹狀數組維護一下就可以啦,又學習了一下樹狀數組:

這裏就直接借用啦題解的文字,學習好算法就好啦,解題思路也要認真學習一下,真正的學習了樹狀數組的維護,學習啦;

利用樹狀數組的維護,這樣子可以在log時間複雜度內將失去的數字減去;

代碼(樹狀數組):

#include<bits/stdc++.h>
const int maxn = 1e6+7;

using namespace std;

int n, q, cnt = 0, tot = 0;

struct Quary{
    int l, r, id;
} Q[maxn];

bool cmp(Quary a, Quary b)
{
    return a.r < b.r;
}

int main()
{
    freopen("in.txt", "r", stdin);
    while(~scanf("%d%d", &n, &q))
    {
        cnt = 0;
        tot = 0;
        vector<int> a(n+1), first(n+1, -1), last(n+1), result(q+1), count(n+1);

        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            last[a[i]] = i;
            if(first[a[i]] == -1) {
                first[a[i]] = i;
                cnt++;
            }
        }

        for(int i = 0; i < q; i++)
        {
            int l, r; scanf("%d%d", &l, &r);
            if(l>=(r-1)) result[i] = cnt;
            else {
                Q[tot].l = l;
                Q[tot].r = r;
                Q[tot++].id = i;
            }
        }

        sort(Q, Q+tot, cmp);

        for(int i = 1, k = 0; i <= n; i++)
        {
            while(k < tot&&Q[k].r == i)
            {
                int &ret = result[Q[k].id] = cnt;
                for(int j = Q[k].l; j < i; j += j&(-j)) ret -= count[j];
                k++;
            }

            if(last[a[i]] == i)
            {
                for(int j = first[a[i]] - 1; j > 0; j -= j&(-j))
                    count[j]++;
            }
        }

        for(int i = 0; i < q; i++) printf("%d\n", result[i]);
    }
    return 0;
}

 

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