首页 > 其他分享 >【CDQ分治】三元环

【CDQ分治】三元环

时间:2024-08-06 20:52:00浏览次数:6  
标签:return int auto sum 分治 mid CDQ 三元 bit

三元环

HDU - 7439

思路

考虑 \(3\) 个点的有向图,要么成环,要么有一个点入度为 \(2\) ,假设第 个点的入度为 \(d_i\),答案为 \(C_n^3-\sum\limits_{i=1}^nC_{d_i}^2\)。

根据题目关系,\(i\rightarrow j\) 当且仅当 \(i<j \ and\ f_i <f_j \ and\ g_i < g_j\),否则就是 \(j\rightarrow i\),所以根据这个三维关系,我们可以先根据前两维求出 \(i<j\ and\ f_i\ge f_j\) 的入度,然后通过 cdq分治去求满足这个三维关系的各点的度数。

代码

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

template<typename T>
struct BIT {
#ifndef lowbit
#define lowbit(x) (x & (-x));
#endif
    int n;
    vector<T> t;

    BIT () {}
    BIT (int _n): n(_n) { t.resize(_n + 1); }
    BIT (int _n, vector<T>& a): n(_n) {
        t.resize(_n + 1);
        for (int i = 1; i <= n; ++ i) {
            t[i] += a[i];
            int j = i + lowbit(i);
            if (j <= n) t[j] += t[i];
        }
    }
    //单点修改
    void update(int i, T x) {
        while (i <= n) {
            t[i] += x;
            i += lowbit(i);
        }
    }
    //区间查询
    T sum(int i) {
        T ans = 0;
        while (i > 0) {
            ans += t[i];
            i -= lowbit(i);
        }
        return ans;
    }

    T query(int i, int j) {
        return sum(j) - sum(i - 1);
    }
    //区间修改则存入差分数组,[l, r] + k则update(x,k),update(y+1,-k)
    //单点查询则直接求前缀和sum(x)

    //求逆序对
    /*
    iota(d.begin(), d.end(), 0);
    stable_sort(d.begin(), d.end(), [&](int x, int y) {
        return a[x] < a[y];
    });去重排序

    BIT<i64> tree(n);
    i64 ans = 0;
    for (int i = 1; i <= n; i ++) {
        tree.update(d[i], 1);
        ans += i - tree.sum(d[i]);
    }
    */
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<array<int, 3>> a(n + 1);
    for (int i = 1; i <= n; i ++) {
        cin >> a[i][0];
        a[i][2] = i;
    }

    for (int i = 1; i <= n; i ++) {
        cin >> a[i][1];
    }

    BIT<i64> bit(n);
    vector<int> in(n + 1);
    //求 i < j and fi >= fj
    for (int i = n; i >= 1; i --) {
        in[i] += bit.sum(a[i][0]);
        bit.update(a[i][0], 1);
    }

    for (int i = n; i >= 1; i --) {
        bit.update(a[i][0], -1);
    }

    auto cdq = [&](auto && self, int l, int r)->void{
        if (l == r)
            return ;

        int mid = l + r >> 1;
        self(self, l, mid);
        self(self, mid + 1, r);

        sort(a.begin() + l, a.begin() + mid + 1, [](auto x, auto y) {
            if (x[0] != y[0]) return x[0] < y[0];
            return x[1] < y[1];
        });

        sort(a.begin() + mid + 1, a.begin() + r + 1, [](auto x, auto y) {
            if (x[0] != y[0]) return x[0] < y[0];
            return x[1] < y[1];
        });

        //求 i < j and fi < fj and gi < gj
        int i = l, j = mid + 1;
        while (j <= r) {
            while (i <= mid && a[i][0] < a[j][0]) {
                bit.update(a[i][1], 1);
                i ++;
            }
            in[a[j][2]] += bit.sum(a[j][1] - 1);
            j ++;
        }
        for (int k = l; k < i; k ++) {
            bit.update(a[k][1], -1);
        }

        //求 i < j and fi < fj and gi >= gj
        i = mid, j = r;
        while (i >= l) {
            while (j > mid && a[j][0] > a[i][0]) {
                bit.update(a[j][1], 1);
                j --;
            }
            in[a[i][2]] += bit.sum(a[i][1]);
            i --;
        }
        for (int k = r; k > j; k --) {
            bit.update(a[k][1], -1);
        }
    };

    cdq(cdq, 1, n);

    i64 ans = 1ll * n * (n - 1) * (n - 2) / 6;
    for (int i = 1; i <= n; i ++) {
        ans -= 1ll * in[i] * (in[i] - 1) / 2;
    }

    cout << ans << '\n';

    return 0;
}

标签:return,int,auto,sum,分治,mid,CDQ,三元,bit
From: https://www.cnblogs.com/Kescholar/p/18345961

相关文章

  • 【CDQ分治】【模板】三维偏序(陌上花开)
    P3810【模板】三维偏序(陌上花开)-洛谷|计算机科学教育新生态(luogu.com.cn)#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;template<typenameT>structBIT{#ifndeflowbit#definelowbit(x)(x&(-x));#endifintn;vector<T&......
  • 【CDQ分治】[P5094 [USACO04OPEN] MooFest G 加强版
    P5094[USACO04OPEN]MooFestG加强版-洛谷|计算机科学教育新生态(luogu.com.cn)#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);intn;cin>>n;vecto......
  • [算法] 一些分治
    普通分治其实没啥,每次只计算跨越分治中心的区间的贡献,剩下的递归到左右两边进行分治;时间复杂度:分治树高度为$\Theta(\logn)$,乘上其他操作的复杂度即可;例题一:现在有一个$n$阶排列$a$,计算:\[\sum^{n}_{i=1}\sum^{n}_{j=i}\min(a_i,a_{i+1},...,a_j)\]......
  • 20240806:点分治,虚树选做
    POJ-1741Tree题意:给定一棵树,求多少无序对\((u,v)\)满足\(\text{dist}(u,v)\lek\)。对于树上的路径进行分类:经过根;不经过根。第二类路径点可以通过递归子树求出。对于经过根的路径,可以一遍dfs求出每个点到根的距离\(\text{dis}(u)\)。问题转化为求\(\text{dis}(u)......
  • CDQ分治
    CDQ分治CDQ分治是一种思想而不是具体的算法,与动态规划类似。目前这个思想的拓展十分广泛,依原理与写法的不同,大致分为三类:解决和点对有关的问题。1D动态规划的优化与转移。通过CDQ分治,将一些动态问题转化为静态问题。解决和点对有关的问题这类问题多数类似于「给定一......
  • 根号分治(待补充)
    最近有根号分治的题都没那么熟悉,想到了方向感也很差,故写一点题解。LCA查询看到题目中的条件\(\sumk\le10^5\)说明\(k\leS\)的个数很多,\(S\lek\)的个数很少。那么对于前者,考虑一开始最朴素的\(O(S^2)\)的暴力,枚举集合中的两个点,求\(LCA\)总时间复杂度\(O(\fra......
  • 「Day 2—贪心问题&分治&前缀和」
    贪心问题定义顾名思义,越贪越好。。。习题P1094[NOIP2007普及组]纪念品分组思路简单来说:最少的+最多的,利用双指针。代码#include<algorithm>#include<iostream>usingnamespacestd;intw,n;intp[30005];intmain(){cin>>w;cin>>n;for(inti=1;i......
  • 边分治维护强连通分量(CF1989F,P5163)
    这里的边分治和树上的点分治边分治不一样,是维护强连通分量用的,每条边有一个出现时间,通过将每条边按连通关系分流重新排列,从而维护每个时间点整张图的连通性。具体的,这个算法是维护这样的一类问题:n个点,m条边按时间顺序依次加入,每加入一条边,你需要回答一些问题,比如在这个时间点......
  • 树分治
    点分治点分治适合处理大规模的树上路径信息问题。LuoguP4178Tree给定一棵有\(n\)个点的带权树,给出\(k\),询问树上距离小于等于\(k\)的点对数量。分治地考虑每一个子树,求出重心,对答案有贡献的是三种点对,依次解决。重心-子树上的点直接累加贡献即可。子树上的点......
  • cdq分治
    cdq分治主要思想为分治,分为三个部分:左区间内部。左区间对右区间。右区间内部。一个保险的标准顺序是先处理左区间,再处理左区间对右区间的贡献,最后处理右区间,这样就可以保证时序性了。注意这种写法在处理左区间对右区间贡献是要先按标号排序分出正确的左右区间,如果是先递归......