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