CF 1000F One Occurrence

2023-05-16

          • 传送门
          • 题目大意
          • 思路
          • 参考代码
          • 总结

时光如梭,Codeforces 的题号还是三位数的时代已经过去;量子语言原来已经来临。

传送门
题目大意

给定一个长度为 n n 的序列 a,有 m m 个询问,每次询问给定一个区间 [l,r],如果这个区间里存在恰好只出现一次的数,输出这个数(如果有多个就任意输出一个),否则输出 0 0

n,m5×105 ai105 a i ≤ 10 5

思路

还好题解是英文的看不懂啊哈哈哈。

首先题解中有三个类型:主席树,线段树,基于莫队的算法(Mo-based algorithm,出题人不是中国的,真神仙),然后我瞄了第一句话:如果所有询问右端点一样……然后我就自己想了……

不妨求出每个位置下一个与它相同的数所在的位置, O(n) O ( n ) 扫描即可,我们用一个从前往后的箭头表示这个东西。发现,如果区间内存在恰好只出现一次的数,那么这个数必须满足两个条件:指向它的箭头不存在或者起点在左端点外;它指向其它位置的箭头在右端点外(如果没有,不妨令这个箭头指向 n+1 n + 1 )。

假设一个区间内所有位置都不存在指向它的箭头,怎么判断这个区间是否有解呢?直接取这个区间内指向别的地方的位置的最大值,拿它和右端点比较即可,这个可以用线段树维护。现在有些位置有箭头指向它,换句话说,有些位置在求最大值时不能算进对答案的贡献中。

考虑把询问按左端点离线,从左到右处理。对于有箭头指向它的位置,我们让它的箭头指向的位置减去一个极大值,然后在区间中取最大值即可。当处理完一个左端点后,如果左端点指向了某个位置,我们就把那个位置指向的位置加上之前减去的那个极大值,这样就能正确统计答案了。用线段树维护,时间复杂度 O(nlogn) O ( n log ⁡ n )

参考代码
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cassert>
#include <cctype>
#include <climits>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <bitset>
#include <list>
#include <functional>
typedef long long LL;
typedef unsigned long long ULL;
using std::cin;
using std::cout;
using std::endl;
typedef int INT_PUT;
INT_PUT readIn()
{
    INT_PUT a = 0; bool positive = true;
    char ch = getchar();
    while (!(ch == '-' || std::isdigit(ch))) ch = getchar();
    if (ch == '-') { positive = false; ch = getchar(); }
    while (std::isdigit(ch)) { a = a * 10 - (ch - '0'); ch = getchar(); }
    return positive ? -a : a;
}
void printOut(INT_PUT x)
{
    char buffer[20]; int length = 0;
    if (x < 0) putchar('-'); else x = -x;
    do buffer[length++] = -(x % 10) + '0'; while (x /= 10);
    do putchar(buffer[--length]); while (length);
    putchar('\n');
}

const int INF = (~(int(1) << (sizeof(int) * 8 - 1))) >> 1;
const int maxn = int(5e5) + 5;
int n, m;
int a[maxn];
struct Query
{
    int l, r;
    void read()
    {
        l = readIn();
        r = readIn();
    }
} querys[maxn];
std::vector<int> offline[maxn];

int appear[maxn];
int next[maxn];
bool pointer[maxn];
class SegTree
{
    static inline int code(int l, int r)
    {
        return (l + r) | (l != r);
    }
    struct Node
    {
        int maxVal;
        int maxIdx;
        Node() : maxVal(-INF - 1) {}
        bool operator<(const Node& b) const
        {
            return maxVal < b.maxVal;
        }
    } nodes[maxn * 2];

    int g_Pos, g_Val, g_L, g_R;
    void update(int l, int r)
    {
        Node& t = nodes[code(l, r)];
        int mid = (l + r) >> 1;
        Node& lc = nodes[code(l, mid)];
        Node& rc = nodes[code(mid + 1, r)];
        if (lc.maxVal >= rc.maxVal)
            t = lc;
        else
            t = rc;
    }
    void add_(int l, int r)
    {
        if (l == r)
        {
            nodes[code(l, r)].maxVal += g_Val;
            return;
        }
        int mid = (l + r) >> 1;
        if (g_Pos <= mid) add_(l, mid);
        else add_(mid + 1, r);
        update(l, r);
    }
    Node query_(int l, int r)
    {
        if (g_L <= l && r <= g_R)
        {
            return nodes[code(l, r)];
        }
        int mid = (l + r) >> 1;
        Node ret;
        if (g_L <= mid)
            ret = std::max(ret, query_(l, mid));
        if (g_R > mid)
            ret = std::max(ret, query_(mid + 1, r));
        return ret;
    }

public:
    void build(int l, int r)
    {
        if (l == r)
        {
            Node& t = nodes[code(l, r)];
            t.maxVal = -INF + next[l];
            t.maxIdx = a[l];
            return;
        }
        int mid = (l + r) >> 1;
        build(l, mid);
        build(mid + 1, r);
        update(l, r);
    }
    void add(int pos, int val)
    {
        g_Pos = pos;
        g_Val = val;
        add_(1, n);
    }
    int query(int l, int r)
    {
        g_L = l;
        g_R = r;
        Node t = query_(1, n);
        if (t.maxVal > r)
            return t.maxIdx;
        else
            return 0;
    }
} st;

int ans[maxn];

void run()
{
    n = readIn();
    for (int i = 1; i <= n; i++)
        a[i] = readIn();
    m = readIn();
    for (int i = 1; i <= m; i++)
        querys[i].read();

    for (int i = 1; i <= m; i++)
        offline[querys[i].l].push_back(i);

    for (int i = n; i; i--)
    {
        next[i] = appear[a[i]];
        if (!next[i]) next[i] = n + 1;
        appear[a[i]] = i;
    }
    for (int i = 1; i <= n; i++)
        if (next[i])
            pointer[next[i]] = true;
    st.build(1, n);
    for (int i = 1; i <= n; i++)
        if (!pointer[i])
            st.add(i, INF);

    for (int l = 1; l <= n; l++)
    {
        for (int i = 0; i < offline[l].size(); i++)
        {
            int idx = offline[l][i];
            int r = querys[idx].r;
            ans[idx] = st.query(l, r);
        }
        if (next[l] <= n)
            st.add(next[l], INF);
    }
    for (int i = 1; i <= m; i++)
        printOut(ans[i]);
}

int main()
{
    run();
    return 0;
}
总结

要是一眼题解都不看就会做就好了。唉,谁叫我太弱了呢 QAQ。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CF 1000F One Occurrence 的相关文章

随机推荐

  • Luogu 1712 [NOI 2016] 区间

    传送门思路参考代码 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 xff0c 这么个傻逼题 xff0c 居然把离散化写错了 xff0c 唉 xff0c 我太弱啦 xff01 显然我们可以考虑枚举最短长度和最长长度 xff0
  • CF 977F Consecutive Subsequence

    传送门思路参考代码 传送门 思路 CF 的第一场 div3 xff0c 在我提交了一份有错的代码后突然不能提交了 xff0c 在跑什么 System Testing xff0c 我就跟它杠上了 xff0c 直到它评测完 唉 xff0c 我太
  • CF 7D Palindrome Degree

    传送门思路参考代码 传送门 思路 不是马拉车加随便 DP 乱搞 xff1f 本来想复习一下马拉车的 xff0c 结果拉出了许多事端 xff08 修复了 OI Learner Judge 的严重 bug 一个害我调了两节课的 bug xff0
  • Luogu 3822 [NOI 2017] 整数

    传送门思路参考代码 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 xff0c 当年网同这道题还拿了 16 16 分 xff0c 现在一分都不会做了 xff0c 唉 xff0c 我太弱啦 xff01 这道题其实是很不错的 x
  • 【Go】go语言中切片的长度变化后容量的变化

    一 新增信息长度 43 当前长度 lt 61 当前容量 span class token keyword func span span class token function printSlice span span class toke
  • APIO 2018 Practice Session T1 Wedding cake

    没有传送门题目大意思路参考代码熟悉环境 没有传送门 题目大意 给你一个长度为 n n 的正整数序列 a i ai xff0c 要求构造出 n n 个小数 使得它们的和为 1 1 xff0c 且每个数小数点后恰好有
  • APIO 2018 Practice Session T3 / CF 936C Lock Puzzle

    传送门题目大意思路参考代码总结 传送门 题目大意 给你一个字符串 origin xff0c 一个字符串 target xff0c 长度均为 n n 要求在 3 n 3n xff08 5 2 n 5 2
  • APIO 2018 游记

    Day 0Day 1Day 2Day 3Day 4 Day 0 早上 4 4 点就上车去机场赶那 7 7 点的飞机 感觉很困 xff0c 所以在飞机上就这么睡过去了 北京是个好地方 xff0c 但是与我无关 下飞机后 xff0c 我们一行人
  • Luogu 2375 [NOI 2014] 动物园

    文章目录 传送门思路参考代码Review 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 xff0c 连 KMP 也不会 xff0c WA 飞了 xff0c 唉 xff0c 我太弱啦 xff01 首先 xff0c 原始的 K
  • Luogu 2114 [NOI 2014] 起床困难综合症

    传送门思路参考代码 传送门 思路 按位贪心 但是我太弱了 xff0c 明明可以 O n O n 预处理 xff0c 我却只会 O 32 n O
  • Luogu 2354 [NOI 2014] 随机数生成器

    传送门思路参考代码 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 xff0c 这么一个傻逼题 xff0c 我却看成了要你构造一种交换方案使得答案最小 xff0c 结果后面的额外交换是题目给定的 唉 xff0c 我太弱啦 x
  • Luogu 2305 [NOI 2014] 购票

    传送门思路别人家的题解弱化的传送门 xff08 Luogu 3994 高速公路 xff09 参考代码 对于没有距离限制的 50 分 参考代码 对于 100 分的数据参考代码Remarks 传送门 思路 唉 xff0c 我太弱了 xff0c
  • Luogu 1224 [NOI 2013] 向量内积

    传送门思路参考代码 传送门 思路 唉 xff0c 我太弱了 xff0c 什么都不会 xff0c 听都没有听说过这类题 xff0c 唉 xff0c 我太弱啦 xff01 显然这道题可以在 O n 2 d O n 2
  • Luogu 1397 [NOI 2013] 矩阵游戏

    传送门思路正解参考代码Remarks 传送门 思路 唉 xff0c 我太弱了 xff0c T1 都做不来 xff0c 唉 xff0c 我太弱啦 xff01 显然这个题可以用矩阵快速幂在 O log n O log n
  • Luogu 2414 [NOI 2011] 阿狸的打字机

    文章目录 传送门思路参考代码总结 传送门 思路 首先我们甚至不能单独保存每个字符串 xff0c 因为总长度可以达到 O n 2
  • kali新手入门教学(10)--ping的讲解

    Ping 是 Windows 和 Linux 都自带的一个扫描工具 xff0c 用于校验与远程计算机或本机的连接 只有在安装 TCP IP 协议之后才能使用该命令 Ping 命令通过向计算机发送 ICMP 回应 报文并且监听回应报文的返回
  • Luogu 3628 [APIO 2010] 特别行动队

    传送门思路参考代码 传送门 BZOJ 思路 设 f i f i 表示将 1 i 1 i 的士兵编
  • Luogu 1399 [NOI 2013] 快餐店

    传送门思路参考代码Remarks总结 传送门 思路 发现这是一棵环套树 那首先我们会想到树上的情况 如果这是一棵树 xff0c 我们自然会联想到树的直径 xff0c 自然会想到对于树而言 xff0c 答案为直径长度的一半 证明 用反证法 假
  • GDB for C++ in Linux

    这篇文章主要讲讲如何在 Linux 下使用 GDB xff0c 当然 xff0c 就指令而言在 Windows 下也适用 环境Items 编译启动退出加载文件查看源代码断点 插入断点删除断点 运行程序查看变量控制程序执行 继续下一步单步进入
  • CF 1000F One Occurrence

    传送门题目大意思路参考代码总结 时光如梭 xff0c Codeforces 的题号还是三位数的时代已经过去 xff1b 量子语言原来已经来临 传送门 题目大意 给定一个长度为 n n 的序列 a a xff0c 有 m m 个