题目
https://codeforces.com/contest/1701/problem/F
样例
input
7 5
8 5 3 2 1 5 6
output
0
0
1
2
5
1
5
思路
这里有官方题解
https://codeforces.com/blog/entry/104671
- 考虑每个存在的点 i ,令在它右边d范围,即 [i+1, i+d] 范围内的点的个数为 f(i)那,那么当 i 为左端点时,右边两个点就是这f(i)个点里面随便选两个。每个时刻的答案就是所有的
f(i)*(f(i)-1)/2
之和。 f(i)*(f(i)-1)/2 = (f(i)^2 - f(i)) /2
- 用线段树维护
f(i)^0, f(i)^1, f(i)^2
。其中f(i)^0
代表存在的点的个数。 - 每加/减一个点,那么它左边d个数的 f(i) 均加/减 1,f(i)^2 相应可以用
f(i)
、f(i)^0
更新出来。新加的那个点的 f(i) 值就为它右边d个位置的点的个数,即f(i)^0
的区间和。
时间复杂度,每个询问都是几个查询修改,所以是 O(q*Log)。
线段树最大线段长度是 a[i] 的最大值,即 200000。
代码
#include <bits/stdc++.h>
using namespace std;
template<typename t_val>
struct trip {
t_val v0, v1, v2;
trip(): v0(0), v1(0), v2(0) {}
void operator+= (const trip<t_val> x) {
v0 += x.v0;
v1 += x.v1;
v2 += x.v2;
}
};
template<typename t_val, int maxn>
struct segment_tree {
#define LX(x) ((x)<<1)
#define RX(x) (((x)<<1)|1)
struct node {
int l, r;
t_val val_0;
t_val val_1;
t_val val_2;
t_val tag;
};
node a[maxn*5+10];
void down_tag(int x) {
if (!a[x].tag) return;
const int lx=LX(x), rx=RX(x);
a[lx].val_2 += a[lx].val_1 * 2*a[x].tag;
a[lx].val_2 += a[lx].val_0 * a[x].tag*a[x].tag;
a[lx].val_1 += a[lx].val_0 * a[x].tag;
a[LX(x)].tag+=a[x].tag;
a[rx].val_2 += a[rx].val_1 * 2*a[x].tag;
a[rx].val_2 += a[rx].val_0 * a[x].tag*a[x].tag;
a[rx].val_1 += a[rx].val_0 * a[x].tag;
a[RX(x)].tag+=a[x].tag;
a[x].tag=0;
}
void merge(int x) {
const int lx=LX(x), rx=RX(x);
a[x].val_0 = a[lx].val_0 + a[rx].val_0;
a[x].val_1 = a[lx].val_1 + a[rx].val_1;
a[x].val_2 = a[lx].val_2 + a[rx].val_2;
}
void build(int x, int l, int r) {
a[x].l=l, a[x].r=r;
if (l==r) {
a[x].val_0 = 0;
a[x].val_1 = 0;
a[x].val_2 = 0;
a[x].tag = 0;
return;
}
build(LX(x), l, (l+r)>>1);
build(RX(x), ((l+r)>>1)+1, r);
merge(x);
}
void modify_conv0(int x, int pos, t_val val) {
if (a[x].l == a[x].r) {
if (a[x].val_0) { // del
a[x].val_0 = 0;
a[x].val_1 = 0;
a[x].val_2 = 0;
a[x].tag = 0;
}
else { // add
a[x].val_0 = 1;
a[x].val_1 = val;
a[x].val_2 = val*val;
a[x].tag = 0;
}
return;
}
down_tag(x);
const int lx=x<<1, rx=(x<<1)|1;
if (a[lx].r >= pos)
modify_conv0(lx, pos, val);
else
modify_conv0(rx, pos, val);
merge(x);
}
void modify_adds(int x, int L, int R, t_val val) {
if (L <= a[x].l && a[x].r <= R) {
a[x].val_2 += a[x].val_1 * 2*val;
a[x].val_2 += a[x].val_0 * val*val;
a[x].val_1 += a[x].val_0 * val;
a[x].tag += val;
return;
}
down_tag(x);
const int lx=x<<1, rx=(x<<1)|1;
if (a[lx].r >= L)
modify_adds(lx, L, R, val);
if (a[rx].l <= R)
modify_adds(rx, L, R, val);
merge(x);
}
trip<t_val> query(int x, int L, int R) {
trip<t_val> tmpl, tmpr, ret;
if (L <= a[x].l && a[x].r <= R) {
ret.v0 = a[x].val_0;
ret.v1 = a[x].val_1;
ret.v2 = a[x].val_2;
return ret;
}
down_tag(x);
const int lx=x<<1, rx=(x<<1)|1;
if (a[lx].r >= L)
tmpl = query(lx, L, R);
if (a[rx].l <= R)
tmpr = query(rx, L, R);
ret += tmpl;
ret += tmpr;
return ret;
}
#undef LX
#undef RX
};
const int MAXN=200000;
segment_tree<long long, MAXN> TT;
void solve()
{
TT.build(1, 1, MAXN);
vector<int> used(MAXN+5);
int q, d;
long long ans;
scanf("%d%d", &q, &d);
for (int i=0, aa; i<q; i++) {
scanf("%d", &aa);
trip<long long> tmp_trip;
if (aa<MAXN) tmp_trip = TT.query(1, aa+1, min(aa+d, MAXN));
TT.modify_conv0(1, aa, tmp_trip.v0);
if (aa>1) TT.modify_adds(1, max(aa-d, 1), aa-1, used[aa] ? -1 : 1);
used[aa]^=1;
tmp_trip = TT.query(1, 1, MAXN);
ans = (tmp_trip.v2-tmp_trip.v1)/2;
printf("%lld\n", ans);
}
}
int main()
{
solve();
return 0;
}
/*
7 5
8 5 3 2 1 5 6
0
0
1
2
5
1
5
*/