FZU 2236 第十四个目标 (线段树)

http://acm.fzu.edu.cn/problem.php?pid=2236

思路:每次找到当前第i个数之前有多少个比第i个数小的数,将前边的情况累加起来并且加上1

线段树查找,离散化

#include <iostream>
#include <stdio.h>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdlib>
#include <algorithm>
using namespace std;

typedef long long LL;
#define N 200000
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define MOD 1000000007
#define met(a, b) memset (a, b, sizeof(a))

const double EPS = 1e-8;

struct node
{
    int l, r, sum;
}tree[N*4];

int val[N], Hash[N];

void Build (int rt, int l, int r)
{
    tree[rt].l = l, tree[rt].r = r;
    tree[rt].sum = 0;

    if (l == r) return;

    int mid = (l+r)/2;

    Build (rt<<1, l, mid);
    Build (rt<<1|1, mid+1, r);
}

void Insert (int rt, int x, int sum)
{
    tree[rt].sum = (tree[rt].sum+sum) % MOD;

    if (tree[rt].l == tree[rt].r) return;

    int mid = (tree[rt].l+tree[rt].r)/2;

    if (x<=mid) Insert (rt<<1, x, sum);
    else Insert (rt<<1|1, x, sum);
}

int Query (int rt, int l, int r)
{
    if (l > r) return 0;
    if (tree[rt].l == l && tree[rt].r == r)
        return tree[rt].sum;

    int mid = (tree[rt].l+tree[rt].r)/2;

    if (r <= mid) return Query (rt<<1, l, r);
    else if (l > mid) return Query (rt<<1|1, l, r);
    else
    {
        int a = Query (rt<<1, l, mid);
        int b = Query (rt<<1|1, mid+1, r);

        return (a+b)%MOD;
    }
}

int main ()
{
    int n;
    while (scanf ("%d", &n) != EOF)
    {
        for (int i=0; i<n; i++)
        {
            scanf ("%d", &val[i]);
            Hash[i] = val[i];
        }
        Hash[n] = 0;

        sort (Hash, Hash+n+1);

        int hs = unique (Hash, Hash+n+1) - Hash;

        Build (1, 1, hs+1);

        for (int i=0; i<n; i++)
        {
            int id = lower_bound (Hash, Hash+hs+1, val[i])-Hash;
            int sum = Query (1, 1, id-1);
            Insert (1, id, sum+1);
        }
        int ans = Query (1, 1, hs+1);
        printf ("%d\n", ans);
    }
    return 0;
}


你可能感兴趣的:(FZU 2236 第十四个目标 (线段树))