首页 > 其他分享 >luogu P1972 SDOI2009 HH的项链

luogu P1972 SDOI2009 HH的项链

时间:2022-10-20 18:22:06浏览次数:106  
标签:ch int luogu 询问 数组 区间 SDOI2009 P1972 考虑

P1972 SDOI2009 HH的项链 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

维护一个长度同为 \(n\) 的数组 \(b\)。一个指针 \(R\) 从 \(1\) 扫到 \(n\) 并做如下操作:

  • 检查是否有 \(k <R\) 满足 \(a_k = a_R\)。若有,将 \(b_k\) 设为 \(0\)。
  • 将 \(b_R\) 设为 \(1\);
  • 回答所有右端点为 \(R\) 的询问 \([L, R]\),答案就是 \(b\) 在 \([L, R]\) 上的区间和。

举例:\((1, 2, 1, 2, 1, 3)\)。\(R\) 分别为 \(1, 2, 3, 4, 5, 6\) 时,\(b\) 数组的变化:

  • \(R = 1\),\((1, 0, 0, 0, 0, 0)\);
  • \(R = 2\),\((1, 1, 0, 0, 0, 0)\);
  • \(R=3\),\((0, 1, 1, 0, 0, 0)\),此时回答 \([1, 3]\) 时 \(b_1 = 0\),相当于不再统计 \(a_1\)(因为已与 \(a_3\) 重复);
  • \(R = 4\),\((0, 0, 1, 1, 0, 0)\);
  • \(R = 5\),\((0, 0, 0, 1, 1, 0)\);
  • \(R = 6\),\((0,0, 0, 1, 1, 1)\);

对 \(b\) 使用树状数组加速。

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2022-10-20 17:43:24 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2022-10-20 18:10:01
 */
#include <bits/stdc++.h>
inline int read() {
    int x = 0;
    bool flag = true;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-')
            flag = false;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = (x << 1) + (x << 3) + ch - '0';
        ch = getchar();
    }
    if(flag)
        return x;
    return ~(x - 1);
}
inline int lowbit(int x) {
    return x & (-x);
}

const int maxn = (int)1e6 + 5;
const int maxq = (int)1e6 + 5;
const int maxv = (int)1e6 + 5;

int a[maxn], lst[maxv], c[maxn];

int n;
inline void add(int x, int v) {
    for (; x <= n; x += lowbit(x))
        c[x] += v;
    return ;
}

inline int get(int x) {
    int sum = 0;
    for (; x; x -= lowbit(x))
        sum += c[x];
    return sum;
}

typedef std :: pair <int, int> pii;
std :: vector <pii> qst[maxn];
int ans[maxq];

int main() {
    n = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read();
    
    std :: fill(lst + 1, lst + maxv - 3, n + 1);
    
    int q = read();

    for (int i = 1; i <= q; ++i) {
        int l = read(), r = read();
        qst[r].emplace_back(l, i);
    }

    for (int r = 1; r <= n; ++r) {
        int x = a[r];
        add(lst[x], -1);
        add(r, 1);
        lst[x] = r;
        
        for (pii q : qst[r]) {
            int l = q.first, id = q.second;
            ans[id] = get(r) - get(l - 1);
        }
    }

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

思路历程:

考虑区间询问。其实也就是让区间内所有 \(x\) 只被统计一次。

那么考虑一个数组 \(b\)。初始时 \(b\) 都是 \(1\)。然后对于一次询问 \([l, r]\),如果在区间内有三个数 \(i, j, k\) 满足 \(a_i = a_j = a_k\),那么我们只考虑让其中一个 \(b\) 变为 \(1\),比如 \(b_i = 1\),然后其他的 \(b_j = b_k = 0\)。类似这样的操作,只需要查询 \(b\) 在 \([l ,r]\) 内的区间和,就是答案。

那么具体来说让哪个值变为 \(1\) 呢?先考虑最左侧变为 \(1\)。

发现很难高效地完成上面那个 \(b\) 的变化操作。。。每次询问都需要扫一遍 \([l, r]\),别太离谱了,,

那就考虑在整个数组上扫。然后考虑怎么应用到子区间。(丹钓战那题的思想)

发现不同的询问,某个元素的 \(b\) 值是不同的,比如 \((1, 2, 3, 3, 5)\),\([4, 5]\) 的 \(b_4\) 需要是 \(1\),但 \([3, 5]\) 的 \(b_4\) 就会变成 \(0\)。

其实想一下也就是 \(l \le 3\) 的询问里,\(b_4\) 变为 \(0\) 呗。那么肯定考虑离线询问了。

是否每次能回答的询问都是类似于 \(l \le \cdots\) 的形式?对。

上面那个例子中,所有 \(l \le 3\) 的询问的 \(b_4\) 为 \(0\),\(l > 3\) 的询问 \(b_4\) 为 \(1\) 肯定是没有问题的。

考虑维护一个指针 \(L\),倒着扫,每次扫到 \(a_L\),检查一下之前有没有一个 \(a_k\) 等于这个 \(a_L\),如果有就把那个 \(b_k\) 翻成 \(0\)。 然后回答所有左端点为 \(L\) 的询问。

要不翻转一下,维护一个指针 \(R\)。正着扫。(有点别扭)

考虑维护一个指针 \(R\),每次扫到 \(a_R\),检查一下之前有没有一个 \(a_k = a_R\),若有,\(b_k\) 翻为 \(0\)。然后回答所有右端点为 \(R\) 的询问,询问如果是 \([L, R]\) 那就是求 \(b\) 的 \([L, R]\) 区间和。

\(b\) 树状数组加速即可。

标签:ch,int,luogu,询问,数组,区间,SDOI2009,P1972,考虑
From: https://www.cnblogs.com/crab-in-the-northeast/p/luogu-p1972.html

相关文章

  • 【luogu CF1163F】Indecisive Taxi Fee(图论)(分类讨论)
    IndecisiveTaxiFee题目链接:luoguCF1163F题目大意给你一个无向图,每次改一条边的权值(每次都会变回来),问你1~n的最短路长度。思路考虑分类讨论,先找到最短路的路径,然......
  • 【luogu CF1140F】Extending Set of Points(线段树分治)
    ExtendingSetofPoints题目链接:luoguCF1140F题目大意有一个点集,有一个扩展操作是加入符合条件的(x0,y0)直到不能加入位置。符合条件是原来(x0,y0)不存在而且存......
  • luogu P3685 [CERC2016]不可见的整数 Invisible Integers
    题面传送门真的吐了,写了五六个小时。首先我们不考虑两边都能走,只考虑向左走,那么的话如果两个从左到右的集合分别为\(S1,S2\),则\(S1\subsetS2\),且除去\(S1\)已经匹配掉的......
  • luogu P5339 [TJOI2019]唱、跳、rap和篮球 (容斥,指数型母函数,NTT)
    https://www.luogu.com.cn/problem/P5339要求不含1234的方案,反过来求含至少一个1234的方案。钦定存在i个位置有1234,位置的方案是Cn-3i,i.其他n-4i个位置的方案是多重集......
  • 【luogu CF645E】Intellectual Inquiry(DP)(结论)(矩阵乘法)
    IntellectualInquiry题目链接:luoguCF645E题目大意给你一个序列,值域在1~k,然后要你在后面再加上m个数,也要满足值域,然后使得本质不同的子序列个数最多,输出这个数量。......
  • 【luogu P5161】WD与数列(SA)(单调栈)
    WD与数列题目链接:luoguP5161题目大意给你一个序列,问你有多少对区间,长度相同,没有相交部分,而且一个区间里面所有数同时加上某个数可以变成另一个区间。思路首先发现它......
  • luogu P3232 [HNOI2013]游走 (期望, 高斯消元)
    https://www.luogu.com.cn/problem/P3232思路:算出每条边的期望访问次数,将期望访问次数多的赋予小的编号。一条边的期望访问次数=访问点u的期望/u的度+访问点v的期望......
  • luoguP1505旅游(处理边权的树剖)
    /*luogu1505非常简单的处理边权的树剖题。在树上将一条边定向,把这条边的权值赋给这条边的出点树剖的时候不计算lca权值即可*/#include<bits/stdc......
  • Luogu1398
    思路什么毒瘤细节题。考虑如何解决。考虑对这些条件做出进一步的抽象。于是我们做出细致的观察。方便起见,我们横、纵坐标自左往右、自上往下标号。字母之间的关系O......
  • LuoguP2633 Count on a tree
    题意给定一棵\(n\)个节点的树,每个点有一个权值。有\(m\)个询问,每次给你\(u,v,k\),你需要回答\(u\text{xorlast}\)和\(v\)这两个节点间第\(k\)小的点权。其......