Codeforces 675E Trains and Statistic

Trains and Statisti

我们考虑从一个点出发到达所有它后面所有位置所需要的次数和, 如果我们当前在x号点已经走了gg步,

那么我们肯定将x能到达的那些没走过的点标为gg + 1, 然后找到x 到a[ x ]上的a值最大的点y, 然后 x 走到 y,  

然后重复上述过程。 那么我们用一个cnt[ i ]数组表示 <= i的点起始经过 i 这个点的有多少个点, 然后进行计算, 

这时候我们会碰到一个问题, 那些cnt[ i ]个到达 i 的其实位置有可能已经处理掉了一些 i 后面的终点, 我们在

这些起始点转移到 i 之前把重复的减掉就好啦。

 

感觉网上用dp写法更好理解一些。。

#include<bits/stdc++.h>
#define LL 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 ull unsigned long long

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);

int n, a[N];
LL dis[N];
LL cnt[N];

#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
PII mx[N << 2];
void build(int l, int r, int rt) {
    if(l == r) {
        mx[rt].fi = a[l];
        mx[rt].se = l;
        return;
    }
    int mid = l + r >> 1;
    build(lson); build(rson);
    mx[rt] = max(mx[rt << 1], mx[rt << 1 | 1]);
}
PII query(int L, int R, int l, int r, int rt) {
    if(l >= L && r <= R) return mx[rt];
    int mid = l + r >> 1;
    if(R <= mid) return query(L, R, lson);
    else if(L > mid) return query(L, R, rson);
    else return max(query(L, R, lson), query(L, R, rson));
}

int main() {
    scanf("%d", &n);
    for(int i = 1; i < n; i++) scanf("%d", &a[i]), cnt[i] = 0;
    build(1, n - 1, 1);
    LL ans = 0;
    for(int i = 1; i < n; i++) {
        cnt[i]++;
        PII tmp = query(i, a[i], 1, n - 1, 1);
        PII nxt = query(tmp.se, a[tmp.se], 1, n - 1, 1);
        ans += cnt[i] * (a[i] - i);
        ans += 2 * cnt[i] * (n - a[i]);
        ans -= cnt[i] * (tmp.fi - nxt.se);
        cnt[nxt.se] += cnt[i];
    }
    printf("%lld\n", ans);
    return 0;
}

/*
*/

 

posted @ 2019-02-27 15:25  NotNight  阅读(170)  评论(0编辑  收藏  举报