P1972 [SDOI2009]HH的项链

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1972 [SDOI2009]HH的项链相关的知识,希望对你有一定的参考价值。

P1972 [SDOI2009]HH的项链

题意:

给你一个序列,问这个序列中的种类数
n,m,ai<=1e6

题解:

三个方法:莫队(会超时),树状数组,主席树(会超时)

莫队就是裸题,不讲了,复杂度O(n*sqrt(n))

树状数组:
对于若干个区间[l,r],如果他们的r都相等,那么项链中出现的同一个数字,一定只关心最右边的那一个。
比如:1 3 4 5 1
对于r=5的所有询问,第一个位置上的1是没有价值的,因为第五个位置已经出现1,也就是对于所有查询[L,5]区间来说,如果第一个1被算,那么它完全可以用第5个1来代替
因此,我们对所有询问按照r来排序,然后维护一个树状数组。
树状数组的用途:
对于序列:1 2 1 3
我们用pre[i]来表示上一此出现i的位置
对于第一个1,insert(1,1),此时树状数组表示的每个数有1 0 0 0
对于第二个2,insert(2,1),此时1 1 0 0
对于第三个1,因为之前出现过1,所以将之前1的位置删掉,insert(1,-1),然后再把当前1加入insert(3,1).此时就是0 1 1 0
询问[2,3],就是sum(3)-sum(2-1)=2

主席树做法:
对于每个点,我们用nex表示这个点之后最近的颜色相同的点的位置,如果没有就设为n+1.
对于区间询问l~r之间的种类,其实就是求满足(l<=i<=r&&nex[i]>r)的个数,因为如果某个点的next已近超出了这个区间的范围,就说明这个点对答案产生贡献了(其实和树状数组思想是一样的,相同颜色只考虑离r最近的)
这样问题就变成在区间l~r之间权值大于r的个数
复杂度是O(mlogn),也会超时

代码:

莫队

// Problem: P1972 [SDOI2009]HH的项链
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1972
// Memory Limit: 512 MB
// Time Limit: 2000 ms
// Data:2021-08-12 09:19:00
// By Jozky

#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
template <typename T> inline void read(T& x)
{
    T f= 1;
    x= 0;
    char ch= getchar();
    while (0 == isdigit(ch)) {
        if (ch == '-')
            f= -1;
        ch= getchar();
    }
    while (0 != isdigit(ch))
        x= (x << 1) + (x << 3) + ch - '0', ch= getchar();
    x*= f;
}
template <typename T> inline void write(T x)
{
    if (x < 0) {
        x= ~(x - 1);
        putchar('-');
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
    startTime= clock();
    freopen("in.txt", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
    endTime= clock();
    printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
int n, m;
const int maxn= 3e6 + 9;
int a[maxn];
int block;
struct node
{
    int l, r;
    int id;
    bool operator<(const node& x) const
    {
        if (l / block != x.l / block)
            return l < x.l;
        if ((l / block) & 1)
            return r < x.r; // 注意这里和下面一行不能写小于(大于)等于,否则会出错(详见下面的小细节)
        return r > x.r;
    }
} q[maxn];
int ans[maxn];
int vis[maxn];
int tot= 0;
void add(int x)
{
    vis[a[x]]++;
    if (vis[a[x]] == 1)
        tot++;
}
void del(int x)
{
    vis[a[x]]--;
    if (vis[a[x]] == 0)
        tot--;
}

// bool cmp(node a, node b)
// {
// if (a.r / block == b.r / block)
// return a.l < b.l;
// return a.r < b.r;
// }
int main()
{
    //rd_test();
    read(n);
    block= sqrt(n);
    for (int i= 1; i <= n; i++)
        read(a[i]);
    read(m);
    for (int i= 1; i <= m; i++) {
        read(q[i].l);
        read(q[i].r);
        q[i].id= i;
    }
    sort(q + 1, q + 1 + m);
    int l= 1, r= 0;
    for (int i= 1; i <= m; i++) {
        int L= q[i].l, R= q[i].r;
        while (l < L)
            del(l++);
        while (l > L)
            add(--l);
        while (r < R)
            add(++r);
        while (r > R)
            del(r--);
        ans[q[i].id]= tot;
    }
    for (int i= 1; i <= m; i++) {
        printf("%d\\n", ans[i]);
    }
    return 0;
    //Time_test();
}

树状数组

#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
template <typename T> inline void read(T& x)
{
    T f= 1;
    x= 0;
    char ch= getchar();
    while (0 == isdigit(ch)) {
        if (ch == '-')
            f= -1;
        ch= getchar();
    }
    while (0 != isdigit(ch))
        x= (x << 1) + (x << 3) + ch - '0', ch= getchar();
    x*= f;
}
template <typename T> inline void write(T x)
{
    if (x < 0) {
        x= ~(x - 1);
        putchar('-');
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
    startTime= clock();
    freopen("in.txt", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
    endTime= clock();
    printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn= 2e6;
int a[maxn];
struct node
{
    int l, r;
    int id;
} q[maxn];
int sum[maxn];
int ans[maxn];
int n;
int vis[maxn];
bool cmp(node a, node b)
{
    return a.r < b.r;
}
int lowbit(int x)
{
    return x & (-x);
}
void add(int pos, int x)
{
    for (int i= pos; i <= n; i+= lowbit(i)) {
        sum[i]+= x;
    }
}
int query(int pos)
{
    int ans= 0;
    for (int i= pos; i >= 1; i-= lowbit(i)) {
        ans+= sum[i];
    }
    return ans;
}
int query(int l, int r)
{
    return query(r) - query(l - 1);
}
int main()
{
    //rd_test();

    read(n);
    for (int i= 1; i <= n; i++)
        read(a[i]);
    int m;
    read(m);
    for (int i= 1; i <= m; i++)
        read(q[i].l), read(q[i].r), q[i].id= i;
    sort(q + 1, q + 1 + m, cmp);
    int beg= 1;
    for (int i= 1; i <= m; i++) {
        for (int j= beg; j <= q[i].r; j++) {
            if (vis[a[j]])
                add(vis[a[j]], -1);
            add(j, 1);
            vis[a[j]]= j;
        }
        beg= q[i].r + 1;
        ans[q[i].id]= query(q[i].l, q[i].r);
    }
    for (int i= 1; i <= m; i++)
        printf("%d\\n", ans[i]);
    return 0;
    //Time_test();
}

主席树

#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
template <typename T> inline void read(T& x)
{
    T f= 1;
    x= 0;
    char ch= getchar();
    while (0 == isdigit(ch)) {
        if (ch == '-')
            f= -1;
        ch= getchar();
    }
    while (0 != isdigit(ch))
        x= (x << 1) + (x << 3) + ch - '0', ch= getchar();
    x*= f;
}
template <typename T> inline void write(T x)
{
    if (x < 0) {
        x= ~(x - 1);
        putchar('-');
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
    startTime= clock();
    freopen("in.txt", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
    endTime= clock();
    printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn= 2e6 + 9;
int rs[maxn], ls[maxn];
int sum[maxn];
int n;
int a[maxn];
int rt[maxn];
int tot= 0;
int vis[maxn], nex[maxn];
void build(int& o, int l, int r)
{
    o= ++tot;
    sum[o]= 0;
    if (l == r)
        return;
    int mid= (l + r) >> 1;
    build(ls[o], l, mid);
    build(rs[o], mid + 1, r);
}
void update(int& o, int以上是关于P1972 [SDOI2009]HH的项链的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P1972 [SDOI2009]HH的项链

题解P1972 [SDOI2009]HH的项链 - 树状数组

luogu P1972 [SDOI2009]HH的项链

P1972 [SDOI2009]HH的项链

P1972 [SDOI2009]HH的项链

P1972 [SDOI2009]HH的项链