P7530 [USACO21OPEN] United Cows of Farmer John P

https://www.luogu.com.cn/problem/P7530

按照套路,我们记\(pre[i]\)表示上一个和\(i\)相同颜色的位置
考虑扫描线,记\(f[l]\)为每个左端点的答案,用线段树维护就是区间\((pre[r],r-1)\)的\(f[l]\)和

考虑\(i\in[l,r],pre[i]\)显然能作为左端点,把它当系数设为0,假设\(i\)是中间点,那么它可以把\((pre[i],i)\)中可以作为左端点的\(f[l]\)全部加\(1\)
写个带系数的线段树维护即可

code:

#include<bits/stdc++.h>
#define ll long long 
#define N 400050
using namespace std;
#define ls (rt << 1)
#define rs (rt << 1 | 1)
ll s[N << 2], val[N << 2], tg[N << 2], sz[N << 2];
void update(int rt) {
    s[rt] = s[ls] + s[rs], sz[rt] = sz[ls] + sz[rs];
}
void padd(int rt, int o) {
    tg[rt] += o, s[rt] += o * sz[rt], val[rt] += o;
}
void pushdown(int rt) {
    if(tg[rt]) {
        padd(ls, tg[rt]), padd(rs, tg[rt]);
        tg[rt] = 0;
    }
}
void addx(int rt, int l, int r, int x, int o) {
    if(l == r) {
        sz[rt] += o;
        s[rt] += o * val[rt];
        return ;
    }
    pushdown(rt);
    int mid = (l + r) >> 1;
    if(x <= mid) addx(ls, l, mid, x, o);
    else addx(rs, mid + 1, r, x, o);
    update(rt);
}
void add(int rt, int l, int r, int L, int R, int o) {
    if(L > R) return ;
    if(L <= l && r <= R) {
        padd(rt, o);
        return ;
    }
    pushdown(rt);
    int mid = (l + r) >> 1;
    if(L <= mid) add(ls, l, mid, L, R, o);
    if(R > mid) add(rs, mid + 1, r, L, R, o);
    update(rt);
}
ll query(int rt, int l, int r, int L, int R) {
    if(L > R) return 0;
    if(L <= l && r <= R) return s[rt];
    pushdown(rt);
    int mid = (l + r) >> 1; ll ret = 0;
    if(L <= mid) ret = query(ls, l, mid, L, R);
    if(R > mid) ret += query(rs, mid + 1, r, L, R);
    return ret;
}
int n, a[N], pre[N], mp[N];
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]), pre[i] = mp[a[i]], mp[a[i]] = i;

    ll ans = 0;
    for(int i = 1; i <= n; i ++) {
        if(pre[i]) 
            addx(1, 1, n, pre[i], - 1),
            add(1, 1, n, pre[pre[i]] + 1, pre[i] - 1, - 1);
        ans += query(1, 1, n, pre[i] + 1, i - 1);
        addx(1, 1, n, i, 1);
        add(1, 1, n, pre[i] + 1, i - 1, 1);
    }
    printf("%lld", ans);
    return 0;
}
上一篇:Beego框架POST请求接收JSON数据


下一篇:849. 到最近的人的最大距离