首页 > 其他分享 >2024牛客暑期多校训练营8 I Haitang and Ranking 题解

2024牛客暑期多校训练营8 I Haitang and Ranking 题解

时间:2024-08-09 18:27:07浏览次数:9  
标签:Ranking err Haitang int 题解 void rth ++ cntok

乱搞

看到 \(n=1e5\) ,时限3s,存在修改操作,很自然的想到根号分治。

考虑按照时间分治。对每 \(B\) 个交换统一处理, \(B\) 个交换最多有 \(2B\) 个元素改变状态,剩下都不变。那么只要对这 \(2B\) 元素内,暴力枚举,剩下的元素构建数据结构实现二维数点,平面内区间最值。

因为 \(a,b\) 是不变的,那么对于点 \((a,b)\) 一共有 \(n\) 个,预处理出每个点左下角的最大值,和右上角的最小值(经过变换后,也在左下角,所以数点只需要询问前缀最值,树状数组实现即可)。左下角的点都要小于自己,右上角的点都大于自己,那么这个点就是合法点。当每个点都是合法点的时候,即可输出 Yes 。如果不变的点内部已经不合法,那么这 \(B\) 个交换结束状态一定都是不合法的。时间复杂度 \(O(\frac{n}{B} \times n log(n))\) 。

考虑要改变状态的 \(2B\) 个点,对于不变的点,二维数点已经处理出是否合法,对于一样要改变的点。维护一个数组 \(err\) ,维护左下角的点有多少点比自己大。维护一个 \(cntok\) 为合法点数量,当 \(err=0\) 且对于不修改的点都成立时,\(cntok+1\) 。每次交换重新算交换点的 \(err\) ,和这个点对其他点的 \(err\) 影响即可,注意这两个点内部影响特判。时间复杂度 $ O(\frac{n}{B} B \times 2B) $ 。

总共的时间复杂度为 $ O(\frac{n^2}{B} log(n) + nB)$ ,取 \(B=\sqrt{n log(n)}\) 时最优,时间复杂度 \(O(n \sqrt{n log(n)})\) 。因为每个块交互元素可以到 \(2B\) 且多次循环,且树状数组常数小,所以代码设置块长偏大,这里设置 \(siz = 2000\) 。

#include <bits/stdc++.h>
#define ll long long
#define enl putchar('\n')
#define all(x) (x).begin(),(x).end()
#define debug(x) printf(" "#x":%d\n",x);
using namespace std;
const int MAXN = 1e5 + 5;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
typedef pair<int, int> pii;
char buf[1 << 21], * p1 = buf, * p2 = buf, obuf[1 << 21], * o = obuf, of[35];
#define gc()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline ll qpow(ll a, ll n) { ll res = 1; while (n) { if (n & 1)res = res * a % mod; n >>= 1; a = a * a % mod; }return res; }
template <class T = int>inline T read() { T s = 0, f = 1; char c = gc(); for (; !isdigit(c); c = gc())if (c == '-')f = -1; for (; isdigit(c); c = gc())s = s * 10 + c - '0'; return s * f; }
inline void read(int* a, int n) { for (int i = 1; i <= n; ++i)a[i] = read(); }
inline int inal(char* s) { int n = 0; for (s[0] = gc(); !isalpha(s[0]); s[0] = gc()); for (; isalpha(s[n]); s[++n] = gc()); return s[n] = 0, n; }
inline void outd(auto* a, int n) { for (int i = 1; i <= n; ++i)printf("%d ", a[i]); enl; }
int n, m, q;

struct P { int operator()(const int& x, const int& y)const { return max(x, y); } };
struct PP { int operator()(const int& x, const int& y)const { return min(x, y); } };


template<class T, int bas>
struct BIT {
    T opt;
    int tr[MAXN], n;
    BIT() { n = MAXN - 1; }
    void setlim(int x) { n = x; }
    void clear() { memset(tr, bas, sizeof(tr)); }
    int lowbit(int x) { return x & -x; }
    void add(int x, int k) { for (; x <= n; x += lowbit(x))tr[x] = opt(tr[x], k); }
    int ask(int x) { int res = bas; for (; x; x -= lowbit(x))res = opt(res, tr[x]); return res; }
};


template<class T, int bas>
struct SMP : BIT<T, bas> {
    array<int, 3> pt[MAXN];
    array<int, 3>qry[MAXN];
    int ans[MAXN];
    int n, m;
    void clear() {
        n = m = 0;
        BIT<T, bas>::clear();
    }
    void addpt(int x, int y, int val) { pt[++n] = {x, y, val}; }
    void addqry(int x, int y, int id) { qry[++m] = {x, y, id}; }
    void work() {
        sort(pt + 1, pt + n + 1, [&](auto& a, auto& b) {return a[1] < b[1]; });
        sort(qry + 1, qry + m + 1, [&](auto& a, auto& b) {return a[1] < b[1]; });
        for (int i = 1, j = 1; i <= m; ++i) {
            while (j <= n && pt[j][1] <= qry[i][1])BIT<T, bas>::add(pt[j][0], pt[j][2]), ++j;
            ans[qry[i][2]] = BIT<T, bas>::ask(qry[i][0]);
        }
    }
};

SMP<P, 0> smp;
SMP<PP, inf> sm;

const int siz = 2000;
int a[MAXN], b[MAXN], c[MAXN], rk[MAXN];

vector<pii>opt;
bool vis[MAXN];

int err[MAXN], cntok;

void work() {
    memset(vis, 0, sizeof(vis)); smp.clear(); sm.clear();
    memset(err, 0, sizeof(err)); cntok = 0;

    for (auto& [x, y] : opt)
        vis[x] = vis[y] = 1;
    vector<int>rth;
    for (int i = 1; i <= n; ++i) {
        if (vis[i]) {
            rth.push_back(i);
            smp.addqry(a[i], b[i], i);
            sm.addqry(n + 1 - a[i], n + 1 - b[i], i);
        } else {
            smp.addpt(a[i], b[i], c[i]);
            smp.addqry(a[i], b[i], i);
            sm.addpt(n + 1 - a[i], n + 1 - b[i], c[i]);
        }
    }
    smp.work(); sm.work();

    int siz = opt.size();
    int tot = rth.size();


    for (int i = 1; i <= n; ++i)
        if (!vis[i])
            if (smp.ans[i] > c[i]) {
                for (auto& [x, y] : opt)
                    swap(c[x], c[y]);
                for (int j = 1; j <= siz; ++j)
                    printf("No\n");
                opt.clear();
                return;
            }

    sort(all(rth), [&](int x, int y) {return a[x] < a[y]; });

    auto check = [&](int x) -> bool {
        return smp.ans[x] <= c[x] && sm.ans[x] >= c[x];
    };

    for (int i = 0; i < rth.size(); ++i)
        for (int j = 0; j < i; ++j)
            if (b[rth[j]] < b[rth[i]] && c[rth[j]] > c[rth[i]])
                ++err[rth[i]];
    for (int i = 0; i < rth.size(); ++i)
        rk[rth[i]] = i;

    for (auto x : rth)
        if (check(x) && !err[x])
            ++cntok;

    auto del = [&](int x) -> void {
        for (int i = rk[x] + 1; i < rth.size(); ++i)
            if (b[x] < b[rth[i]] && c[x] > c[rth[i]]) {
                --err[rth[i]];
                if (!err[rth[i]] && check(rth[i]))
                    ++cntok;
            }
    };

    auto cal = [&](int x) -> void {
        for (int i = 0; i < rk[x]; ++i)
            if (b[rth[i]] < b[x] && c[rth[i]] > c[x])
                ++err[x];
        for (int i = rk[x] + 1; i < rth.size(); ++i)
            if (b[x] < b[rth[i]] && c[x] > c[rth[i]]) {
                if (!err[rth[i]] && check(rth[i]))
                    --cntok;
                ++err[rth[i]];
            }
        if (check(x) && !err[x])
            ++cntok;
    };

    for (auto& [x, y] : opt) {
        if (x == y) {
            if (cntok == tot)printf("Yes\n");
            else printf("No\n");
            continue;
        }
        if (rk[x] < rk[y])swap(x, y);
        del(x); del(y);
        if (!err[x] && check(x))--cntok;
        if (!err[y] && check(y))--cntok;
        err[x] = err[y] = 0;
        swap(c[x], c[y]);
        int tmp = c[y];
        c[y] = 0; cal(x); c[y] = tmp; cal(y);
        if (cntok == tot)printf("Yes\n");
        else printf("No\n");
    }

    opt.clear();
}

void solve() {
    n = read(), m = read();
    smp.setlim(n), sm.setlim(n);
    read(a, n), read(b, n), read(c, n);
    for (int i = 1; i <= m; ++i) {
        opt.push_back({read(), read()});
        if (i % siz == 0)
            work();
    }
    if (!opt.empty())work();
}
signed main(signed argc, char const* argv[]) {
    clock_t c1 = clock();
#ifdef LOCAL
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    //=============================================================
    int TxT = 1;
    // TxT = read();
    while (TxT--)
        solve();
    //=============================================================
#ifdef LOCAL
    end :
    cerr << "Time Used:" << clock() - c1 << "ms" << endl;
#endif
    return 0;
}


标签:Ranking,err,Haitang,int,题解,void,rth,++,cntok
From: https://www.cnblogs.com/Qing17/p/18351287

相关文章

  • luogu题解:P10456 The Pilots Brothers' refrigerator【缺少 SPJ】
    思路此题题意酷似P10449.费解的开关。https://www.luogu.com.cn/problem/P10449不同之处便是状态连锁改变不同,但做法截然不同,此题是一个\(4\times4\)的矩阵。暴力枚举的复杂度是\(O(10^7)\),即\(2^{16}\times16\times16=16777216\),\(10^7\)的复杂度可以通......
  • P2901题解
    题目大意输出一张有向带权图前k短路的长度思路分析这是道k短路板子题我们可以用Astar算法来实现它OIwiki相关算法的网页简单来讲,Astar定义了一个估值函数f(x)=g(x)+h(x)g(x)表示由起点到达x点的路程(不一定是最短路),而h(x)则是终点到x点的最短路程这个估值函数可以预估从该......
  • Codeforces 165E Compatible Numbers 题解
    思路高维前缀和高维前缀和把数的二进制看成一个集合,二进制的每一位为\(1\)为全集\(V\)。根据题目描述,若两数\(a,b\)相容,则\(a\operatorname{and}b=0\),容易发现,\(b\in\complement_{V}a\),所以我们只需要用高维前缀和处理出\(\complement_{V}a\)的一个元素即可。......
  • ABC349D题解
    [ABC349D]DivideInterval题解传送门:luogu|atcoder题目简述给定非负整数\(l\)和\(r\)(\(l<r\)),令\(S(l,r)\)表示序列\((l,l+1,\ldots,r-2,r-1)\),其中包含从\(l\)到\(r-1\)的所有整数。此外,一个序列被称为“好序列”,当且仅当它可以表示为\(S(2^ij,2^{i}(j+1))\),......
  • AT_past202010_m 筆塗り 题解
    题目传送门前置知识线段树|树链剖分解法观察到要维护树上信息,且更改的呈链状,考虑进行树链剖分。将边权转化成点权,钦定边权给了深度更深的那个点,注意更新时不能更新\(\operatorname{LCA}\)。区间赋值和单点查询用线段树维护即可。代码#include<bits/stdc++.h>usingnam......
  • 如何避免自己问题解决缓慢导致项目周期延长
    在公司实习期间,我发现自己对业务的熟悉程度不足,导致在预期时间和实际完成时间上存在差异。虽然这种情况在后期有所改善,但前期的压力相对较大。为此,我总结了以下几点经验和改进措施:1.问题描述与现有分析我们今天的工作进展如何?当前诊断的调查进展如何?如果进展缓慢,是什么原因?需......
  • ABC349D题解
    [ABC349D]DivideInterval题解传送门:luogu|atcoder题目简述给定非负整数$l$和$r$($l<r$),令$S(l,r)$表示序列$(l,l+1,\ldots,r-2,r-1)$,其中包含从$l$到$r-1$的所有整数。此外,一个序列被称为“好序列”,当且仅当它可以表示为$S(2^ij,2^{i}(j+1))$,其中$i$和$j$......
  • # Cocos通过Electron打包web应用后,在触屏一体机设备触摸滑动无效问题解决
    Cocos通过Electron打包web应用后,在触屏一体机设备触摸滑动无效问题解决已经很晚了,刚刚解决这个问题,还是想记录一下,因为刚刚接触cocos没多久,这个问题困扰了我很久。背景接手了一个答题小游戏,由于涉及敏感信息就不在这里截图了,交接到我手里的是用cocos开发的,之前从来没有接触......
  • P8819题解
    题目大意现在有个有向图图,共有n个点,m条边总共有四种操作:操作1:将一条边打上标记操作2:将一个点出发的所有边打上标记操作3:将一条边移除标记操作4:将一个点出发的所有边移除标记打上标记的边视为被移除每次操作进行一次询问,如果每个点出度都是1,整张图是个强连通图,那么输出"YES......
  • 题解 洛谷P1478 陶陶摘苹果(升级版)
    题目传送门https://www.luogu.com.cn/problem/P1478截图来自洛谷:这道题就是这道题的升级版而已,我们可以定义一个结构体分别存抓当前苹果的力气与高度。之后进行从第1个苹果到第n个苹果的循环,判断当前苹果高度是否够,力气是否够。最重要的是要排序,因为要摘得苹果最多,所以要先......