Codeforces 283E Cow Tennis Tournament 线段树 (看题解)

Cow Tennis Tournament

感觉这题的难点在于想到求违反条件的三元组。。

为什么在自己想的时候没有想到求反面呢!!!!

违反的三元组肯定存在一个人能打败其他两个人, 扫描的过程中用线段树维护一下就好了。

反思: 计数问题: 正难则反 正难则反 正难则反 !!!!

#include<bits/stdc++.h>
#define LL long long
#define LD long double
#define ull unsigned long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define fio ios::sync_with_stdio(false); cin.tie(0);

using namespace std;

const int N = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);

template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;}
template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;}
template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;}
template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;}

int n, k, s[N];
int cntL[N], cntR[N];
vector<int> in[N], ot[N];

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1

struct setmentTree {
    int a[N << 2][2];
    int flip[N << 2];

    inline void pull(int rt) {
        a[rt][0] = a[rt << 1][0] + a[rt << 1 | 1][0];
        a[rt][1] = a[rt << 1][1] + a[rt << 1 | 1][1];
    }
    inline void push(int rt) {
        if(flip[rt]) {
            swap(a[rt << 1][0], a[rt << 1][1]);
            swap(a[rt << 1 | 1][0], a[rt << 1 | 1][1]);
            flip[rt << 1] ^= 1;
            flip[rt << 1 | 1] ^= 1;
            flip[rt] = 0;
        }
    }
    void build(int l, int r, int rt) {
        flip[rt] = 0;
        if(l == r) {
            a[rt][0] = 1;
            a[rt][1] = 0;
            return;
        }
        int mid = l + r >> 1;
        build(lson); build(rson);
        pull(rt);
    }
    void update(int L, int R, int l, int r, int rt) {
        if(R < l || r < L || R < L) return;
        if(L <= l && r <= R) {
            swap(a[rt][0], a[rt][1]);
            flip[rt] ^= 1;
            return;
        }
        push(rt);
        int mid = l + r >> 1;
        update(L, R, lson);
        update(L, R, rson);
        pull(rt);
    }
    PII query(int L, int R, int l, int r, int rt) {
        if(R < l || r < L || R < L) return mk(0, 0);
        if(L <= l && r <= R) return mk(a[rt][0], a[rt][1]);
        push(rt);
        int mid = l + r >> 1;
        PII ret, tmp;
        tmp = query(L, R, lson);
        ret.fi += tmp.fi; ret.se += tmp.se;
        tmp = query(L, R, rson);
        ret.fi += tmp.fi; ret.se += tmp.se;
        return ret;
    }
} Tree;

struct Line {
    int l, r;
} seg[N];

int main() {
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; i++) scanf("%d", &s[i]);
    sort(s + 1, s + 1 + n);
    for(int i = 1; i <= k; i++) {
        int a, b; scanf("%d%d", &a, &b);
        a = lower_bound(s + 1, s + 1 + n, a) - s;
        b = upper_bound(s + 1, s + 1 + n, b) - s - 1;
        seg[i].l = a; seg[i].r = b;
        if(a <= b) {
            in[a].push_back(i);
            ot[b].push_back(i);
        }
    }
    Tree.build(1, n, 1);
    for(int i = 1; i <= n; i++) {
        for(auto &id : in[i]) Tree.update(seg[id].l, seg[id].r, 1, n, 1);
        cntL[i] = Tree.query(1, i - 1, 1, n, 1).fi;
        for(auto &id : ot[i]) Tree.update(seg[id].l, seg[id].r, 1, n, 1);
    }
    Tree.build(1, n, 1);
    for(int i = n; i >= 1; i--) {
        for(auto &id : ot[i]) Tree.update(seg[id].l, seg[id].r, 1, n, 1);
        cntR[i] = Tree.query(i + 1, n, 1, n, 1).se;
        for(auto &id : in[i]) Tree.update(seg[id].l, seg[id].r, 1, n, 1);
    }
    LL ans = 1LL * n * (n - 1) * (n - 2) / 6;
    for(int i = 1; i <= n; i++) {
        ans -= 1LL * cntL[i] * (cntL[i] - 1) / 2;
        ans -= 1LL * cntR[i] * (cntR[i] - 1) / 2;
        ans -= 1LL * cntL[i] * cntR[i];
    }
    printf("%lld\n", ans);
    return 0;
}

/*
*/

原文地址:https://www.cnblogs.com/CJLHY/p/10990265.html

时间: 2024-11-05 14:42:32

Codeforces 283E Cow Tennis Tournament 线段树 (看题解)的相关文章

CodeForces - 283E Cow Tennis Tournament

Discription Farmer John is hosting a tennis tournament with his n cows. Each cow has a skill level si, and no two cows having the same skill level. Every cow plays every other cow exactly once in the tournament, and each cow beats every cow with skil

Codeforces 444C DZY Loves Colors(线段树)

题目大意:Codeforces 444C DZY Loves Colors 题目大意:两种操作,1是修改区间上l到r上面德值为x,2是询问l到r区间总的修改值. 解题思路:线段树模板题. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; const int maxn = 5*1e5; typedef long lo

Codeforces 57B Martian Architecture 暴力||线段树

题目链接:点击打开链接 题意:n长的序列(初始全为0) m个操作 k个查询 下面m个操作[l,r] h 代表 a[l] +=h; a[l+1] += h+i; a[l+i] += h+i;  l<=i<=r 然后问k个位置的和 因为k<=100 所以直接暴力也可以 ----------------------- 如果k<=100000 也是可以做的 只需要给区间记录一个标记lazy,表示从左端点开始 l, l+1, l+i ··· l+r 而向下更新时, 左区间则直接更新, 右区间

283E&amp;EZOJ #89 Cow Tennis Tournament

传送门 分析 我们考虑用所有的情况减去不合法的情况 不难想出所有情况为$C_n^3$ 于是我们考虑不合法的情况 我们知道对于一个不合法的三元组$(a,b,c)$一定是修改后$a<b,b>c$ 于是我们可以离散化后用线段树维护每个点被覆盖了几次 所以每次对于一个点$i$,比它大的点的个数即为在它前面修改次数为偶数的数量加在它后面修改次数为奇数的数量 而产生的不合法情况即为$C_{sum_i}^2$ 我们再统计前后两种情况的时候将修改排序然后分别从后往前和从前往后各跑一次即可 每次只要区间不再覆盖

Codeforces 1076G Array Game 博弈 + 线段树 (看题解)

Array Game 考虑最裸的dp去求胜负态. dp[ i ] 从后面的 m 个状态转移过来. 我们考虑如何用线段树维护, T[ i ][ mask ] 表示 i 这段区间如果后面接的m位是mask使时开头m位的mask, 对于修改的话只要维护一个反过来的T2就可以了. 感觉是可以想出来的题, 为什么没想出来啊啊啊. #include<bits/stdc++.h> #define LL long long using namespace std; const int N = (int)2e5

CodeForces 600E Lomsat gelral(线段树合并)

题目链接:http://codeforces.com/problemset/problem/600/E You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour. Let's call colour c dominating in the subtree of vertex v if there are no other colours that appear in the

codeforces 487B B. Strip(rmq+线段树+二分)

题目链接: codeforces 487B 题目大意: 给出一个序列,要把序列划分成段,每一段最少有L个元素,段中的最大元素和最小元素之差不大于s,问划分的段的最少的数量是多少. 题目分析: 首先用rmq维护区间最大值和区间最小值. 然后按顺序扫描数组,线段树维护的数组,每个记录当前点作为最后一个点的前i个点划分的最小的段数,那么每次更新就是二分找到可以转移到我的最远距离,然后再选取与我距离大于l的那部分,取最小值即可. 最终结果就是线段树维护的数组的最后一个位置的元素的值. AC代码: #in

codeforces 482B. Interesting Array【线段树区间更新】

题目:codeforces 482B. Interesting Array 题意:给你一个值n和m中操作,每种操作就是三个数 l ,r,val.就是区间l---r上的与的值为val,最后问你原来的数组是多少?如果不存在输出no 分析:分析发现要满足所有的区间,而一个点上假如有多个区间的话,这个点的值就是所有区间或的值,因为只有这样才能满足所有区间的,把所有位上的1都保存下来了,那么可以发现用线段树来维护,但是那么怎么判断满不满足条件呢?可以也用线段树,更新了之后在整个维护一遍看看满不满足题意,如

codeforces 374D. Inna and Sequence 线段树

题目链接 给m个数, n个操作, 一个数列, 初始为空.一共有3种操作, 在数列末尾加0, 加1, 或删除位置为a[i]的数, a[i]为初始给的m个数, 如果a[i]大于数列长度, 那么什么也不发生. 求最后的数列. 用线段树, 因为最多只有n个操作, 也就是说最后的01串最大长度为n, 那么可以用一个变量now表示当前插入的话应该插入到哪个位置, 每插入一个数, now就加1,并且now最终不会超过n. 删除操作的话, 递归的进行, 如果sum[rt<<1]大于要删除的下标那么就往左儿子递