其他分享
首页 > 其他分享> > cf1701 F. Points

cf1701 F. Points

作者:互联网

题意:

定义美丽三元组 \(<i,j,k>\):\(i<j<k\) 且 \(k-i\le d\)

给定 \(d\),动态维护一个点集,支持添加点和删除点操作,在每次操作后输出全集中美丽三元组的数量

范围都是 \(2e5\)

思路:

\(f_i\) 表示点 \(i\) 存在的情况下,\([i+1,i+d]\) 中有多少个点。那么答案就是 \(\sum C_{f_i}^2=\frac{f_i(f_i-1)}{2}\)

考虑添加一个点 \(i\) 有啥影响:首先答案要加上 \(f_i(f_i-1)/2\)(\(f_i\) 是修改前的值);然后 \([i-d,i-1]\) 里的每个点 \(j\) 的 \(f\) 值加1,答案增加 \(\frac{(f_j+1)f_j}2-\frac{f_j(f_j-1)}2=f_j\)。所以答案要增加一个 \(f_j\) (修改前的)的区间和

删除点同理。但要注意操作顺序: \(f_i\) 是修改前的;然后答案变化 \(\frac{(f_j-1)(f_j-2)}2-\frac{f_j(f_j-1)}2=-(f_j-1)\) 所以是修改后的值

写一个支持区间修改、区间查询的线段树即可。还要维护每个点是否存在

const signed N = 100 + 2e5;

#define mid (l+r)/2
#define lson u*2
#define rson u*2+1
#define ls lson,l,mid
#define rs rson,mid+1,r

ll sum[N*4], cnt[N*4], lzy[N*4];

void pushup(int u) {
    sum[u] = sum[lson] + sum[rson];
    cnt[u] = cnt[lson] + cnt[rson];
}
void pushdn(int u) {
    if(lzy[u]) {
        sum[lson] += lzy[u] * cnt[lson], lzy[lson] += lzy[u];
        sum[rson] += lzy[u] * cnt[rson], lzy[rson] += lzy[u];
        lzy[u] = 0;
    }
}
void modi(int u, int l, int r, int x, int v, int w) { //单点修改存在性
    if(l == r) {
        cnt[u] = v, sum[u] = w; //记得把sum也清零
        return;
    }
    pushdn(u);
    if(x <= mid) modi(ls, x, v, w);
    else modi(rs, x, v, w);
    pushup(u);
}
void add(int u, int l, int r, int x, int y, int d) { //区间加,sum[]
    if(x <= l && r <= y) {
        sum[u] += cnt[u] * d, lzy[u] += d;
        return;
    }
    pushdn(u);
    if(x <= mid) add(ls, x, y, d);
    if(y > mid) add(rs, x, y, d);
    pushup(u);
}
ll query(int u, int l, int r, int x, int y, ll *arr) {
    if(x <= l && r <= y) return arr[u];
    if(y < l || x > r) return 0;
    pushdn(u);
    ll ans = 0;
    if(x <= mid) ans += query(ls, x, y, arr);
    if(y > mid) ans += query(rs, x, y, arr);
    return ans;
}

void sol() {
    int n=2e5, q, d; cin >> q >> d;
    ll ans = 0;
    while(q--) {
        int i; cin >> i;
        if(query(1,1,n, i, i, cnt)) { //已存在,要删除点
            ll t = query(1,1,n, min(n,i+1), min(n,i+d), cnt);
            add(1,1,n, max(1,i-d), max(1,i-1), -1);
            modi(1,1,n, i, 0, 0);
            ans -= t*(t-1)/2 + query(1,1,n, max(1,i-d), max(1,i-1), sum);
        }
        else { //添加点
            ll t = query(1,1,n, min(n,i+1), min(n,i+d), cnt);
            ans += t*(t-1)/2 + query(1,1,n, max(1,i-d), max(1,i-1), sum);
            add(1,1,n, max(1,i-d), max(1,i-1), 1); //这里取max可能会改到i
            modi(1,1,n, i, 1, t); //所以先区间加再修改比较稳妥
        }
        cout << ans << endl;
    }
}

标签:lzy,cnt,int,max,sum,Points,query,cf1701
来源: https://www.cnblogs.com/wushansinger/p/16477286.html