Educational Codeforces Round 41 967 E. Tufurama (CDQ分治 求 二维点数)

Educational Codeforces Round 41 (Rated for Div. 2)

E. Tufurama (CDQ分治 求 二维点数)

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

One day Polycarp decided to rewatch his absolute favourite episode of well-known TV series "Tufurama". He was pretty surprised when he got results only for season 7 episode 3 with his search query of "Watch Tufurama season 3 episode 7 online full hd free". This got Polycarp confused — what if he decides to rewatch the entire series someday and won't be able to find the right episodes to watch? Polycarp now wants to count the number of times he will be forced to search for an episode using some different method.

TV series have n seasons (numbered 1 through n), the i-th season has *a**i* episodes (numbered 1 through *a**i). Polycarp thinks that if for some pair of integers x* and y (x < y) exist both season x episode y and season y episode x then one of these search queries will include the wrong results. Help Polycarp to calculate the number of such pairs!

Input

The first line contains one integer n (1  ≤ n  ≤  2·105) — the number of seasons.

The second line contains n integers separated by space a1, a2, ..., *a**n* (1 ≤ *a**i* ≤ 109) — number of episodes in each season.

Output

Print one integer — the number of pairs x and y (x < y) such that there exist both season x episode y and season y episode x.

Examples

input

Copy

51 2 3 4 5

output

Copy

0

input

Copy

38 12 7

output

Copy

3

input

Copy

33 2 1

output

Copy

2

Note

Possible pairs in the second example:

  1. x = 1, y = 2 (season 1 episode 2 season 2 episode 1);
  2. x = 2, y = 3 (season 2 episode 3 season 3 episode 2);
  3. x = 1, y = 3 (season 1 episode 3 season 3 episode 1).

In the third example:

  1. x = 1, y = 2 (season 1 episode 2 season 2 episode 1);
  2. x = 1, y = 3 (season 1 episode 3 season 3 episode 1).

题意:

有一部电视剧有n季,每一季有ai集。定义二元组(i,j):存在第i季有第j集。求(i,j)与(j,i)同时合法(i<j)的对数。

真实题意就是:求<i,j>对数,使得a[i]≥j,a[j]≥i并且(i<j)

思路

我们对于第i集,我们建立一个二维坐标(i,a[i] )

通过分析我们发现,对于第i集,可以对答案的贡献就是 \([i+1,a[i]]\) 这个区间集中,集数a[j] >= i 的个数。

我们可以转化为 是询问 二维坐标系中 左下角为\((i+1,i)\) 右上角是 \(([i],n+1)\) 的矩阵中包括的点数。

\(a[i]<=i\) 时,这个第i集对答案一定为0贡献的,

所以记得跳过这种情况。

然后上面就是一个经典的三维偏序问题,我们直接套CDQ分治模板即可。

此题有更简单的树状数组写法,带更。(因为CDQ直接套板子不费脑子)

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {a %= MOD; if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}

inline void getInt(int *p);
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
int op;
int n;
const int maxL = 3000010;
ll tree[maxL];
int lowbit(int x)
{
    return -x & x;
}
ll ask(int x)
{
//    cout << x << " ";
    ll res = 0ll;
    while (x) {
        res += tree[x];
        x -= lowbit(x);
    }
//    cout << res << endl;
    return res;
}
void add(int x, ll val)
{
//    cout << x << " " << val << endl;
    while (x < maxL) {
        tree[x] += val;
        x += lowbit(x);
    }
}

struct node {
    int t;
    int op;
    int x, y;
    int k;
    int val;
    node() {}
    node(int tt, int oo, int xx, int yy, int kk, int vv)
    {
        t = tt;
        op = oo;
        x = xx;
        y = yy;
        k = kk;
        val = vv;
    }
    bool operator<= (const node &bb )const
    {
        if (x != bb.x) {
            return x < bb.x;
        } else {
            return y <= bb.y;
        }
    }
};
node a[maxn];
node b[maxn];
ll ans[maxn];
int tot;
int anstot;


void cdq(int l, int r)
{
    if (l == r) {
        return ;
    }
    int mid = (l + r) >> 1;
    cdq(l, mid);
    cdq(mid + 1, r);
    int ql = l;
    int qr = mid + 1;
    repd(i, l, r) {
        if (qr > r || (ql <= mid && a[ql] <= a[qr])) {
            if (a[ql].op == 1) {
                add(a[ql].y, a[ql].val);
            }
            b[i] = a[ql++];
        } else {
            if (a[qr].op == 2) {
                ans[a[qr].val] += a[qr].k * ask(a[qr].y);
            }
            b[i] = a[qr++];
        }
    }
    ql = l;
    qr = mid + 1;
    repd(i, l, r) {
        if (qr > r || (ql <= mid && a[ql] <= a[qr])) {
            if (a[ql].op == 1) {
                add(a[ql].y, -a[ql].val);
            }
            ql++;
        } else {
            qr++;
        }
    }
    repd(i, l, r) {
        a[i] = b[i];
    }
}
int m;
int c[maxn];

int main()
{
    //freopen("D:\\code\\text\\input.txt","r",stdin);
    //freopen("D:\\code\\text\\output.txt","w",stdout);
    scanf("%d", &n);
    int x1, x2, y1, y2;
    repd(i, 1, n)
    {
        scanf("%d", &c[i]);
        if (c[i] > n)
            c[i] = n;
        tot++;
//        cout<<i<<" , "<<c[i]<<endl;
        a[tot] = node(tot, 1, i, c[i], 0, 1);
    }
    repd(i,1,n)
    {
        if(c[i]<=i)
            continue;
        x1 = i + 1;
        y1 = i;

        x2 = c[i];
        y2 = n+1;
//        cout << x1 << " " << y1 << " " << x2 << " " << y2 << endl;
        tot++;
        a[tot] = node(tot, 2, x1 - 1, y1 - 1, 1, ++anstot);
        tot++;
        a[tot] = node(tot, 2, x1 - 1, y2, -1, anstot);
        tot++;
        a[tot] = node(tot, 2, x2, y1 - 1, -1, anstot);
        tot++;
        a[tot] = node(tot, 2, x2, y2, 1, anstot);
    }
    cdq(1, tot);
    ll temp = 0ll;
    repd(i, 1, anstot) {
        temp += ans[i];
//        printf("%lld\n", ans[i]);
    }
    printf("%lld\n", temp);

    return 0;
}

inline void getInt(int *p)
{
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '\n');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    } else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}
全部评论

相关推荐

暴杀流调参工作者:春招又试了一些岗位,现在投递很有意思,不仅要精心准备简历,投递官网还得把自己写的东西一条一条复制上去,阿里更是各个bu都有自己的官网,重复操作无数次,投完简历卡完学历了,又该写性格测评、能力测评,写完了又要写专业笔试,最近还有些公司搞了AI辅助编程笔试,有些还有AI面试,对着机器人话也听不明白录屏硬说,终于到了人工面试又要一二三四面,小组成员面主管面部门主管面hr面,次次都没出错机会,稍有不慎就是挂。 卡学历卡项目卡论文卡实习什么都卡,没有不卡的😂
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务