F. Points
友情链接:
本篇题解的信息维护和此题类似。
22-湖北省赛-L
题目大意:
求三元组 ( i , j , k ) , i < j < k , k − i < = d (i,j,k),i<j<k,k-i<=d (i,j,k),i<j<k,k−i<=d的个数,动态维护。
思路:
每次加点或者删点,单独考虑包含这个点的三元组即可。(设为
x
x
x)
一个明显的事实是:在一个长度为
d
+
1
d+1
d+1的区间上任选三个存在的点一定是合法三元组。(即
x
x
x作为必选点即可)
考虑一次如何暴力计算。
void work(){
int x; cin>>x;
for(int i=max(1,x-d);i<=x;i++){ // 起点在 (x-d)-x
if(ok(i)){ // 如果起点存在
int num=0;
for(int j=i;j<=j+d;j++){ // 统计 i-(i+d)存在的点的个数
if(ok(j)) num++;
}
if(i!=x) ans+=num-2; // 起点不是x,x和i必选,即Cn1.(num包含了x和i其他任选其一)
else{ // 起点是 x
num--;
if(num>=2){
ans+=num*(num-1)/2; // 任选两个即可
}
}
}
}
}
有了暴力思路思考如何优化。
对于单个点
i
i
i直接让其代表
i
−
i
+
d
i-i+d
i−i+d区间上存在的点的个数。(代替内侧
f
o
r
for
for)
对于所有点用线段树联系起来。(代替外侧
f
o
r
for
for)
接着思考如何维护。
修改点
x
x
x的状态,更新的区间是
(
x
−
d
)
−
x
(x-d)-x
(x−d)−x,直接区间修改即可?
这里有一点点小问题,区间上并非所有起点都存在,直接区间操作,得到的区间和是错误的,如果只操作存在的点时间方面是一个问题,其次当不存在的点
x
x
x加入时其所代表的区间值会偏小。
故还是操作整个区间,不同的是,记录区间真实存在的点的个数,以及真实的区间和,当一个点状态发生变化时修改真实区间和即可。
线段树信息:
struct PW{
ll l,r;
ll num1; // 真值个数
ll lazy;
ll sum1,sum2; //真值和 和
}a[N*4];
pushdown 函数:
void pushdown(int id){
if(a[id].lazy!=0){
a[id<<1].lazy+=a[id].lazy;
a[id<<1|1].lazy+=a[id].lazy;
a[id<<1].sum1+=a[id<<1].num1*a[id].lazy; // 更新真实值
a[id<<1|1].sum1+=a[id<<1|1].num1*a[id].lazy;
a[id<<1].sum2+=(a[id<<1].r-a[id<<1].l+1)*a[id].lazy;
a[id<<1|1].sum2+=(a[id<<1|1].r-a[id<<1|1].l+1)*a[id].lazy; // 更新区间合
}
a[id].lazy=0;
}
修改单点状态
void modify(int id,int x,int num){ // num 状态
if(a[id].l==a[id].r){
a[id].num1=num; // 0|1
a[id].sum1=num*a[id].sum2; // 个数是不保含x的,接着的区间加会加上
}
else{
pushdown(id);
int mid=a[id].l+a[id].r>>1;
if(x<=mid) modify(id<<1,x,num);
else modify(id<<1|1,x,num);
pushup(id);
}
}
主函数在查询时要注意区间合法性。
此外以
x
x
x为起点的答案贡献和其他不同,个人拆开写了。
Code:
#include <iostream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <iomanip>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
//#include <unordered_map>
#define guo312 std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define Inf LONG_LONG_MAX
#define inf INT_MAX
#define endl "\n"
#define PI 3.1415926535898
using namespace std;
const int N=2e5+10;
int q,d;
struct PW{
ll l,r;
ll num1;
ll lazy;
ll sum1,sum2;
}a[N*4];
void pushdown(int id){
if(a[id].lazy!=0){
a[id<<1].lazy+=a[id].lazy;
a[id<<1|1].lazy+=a[id].lazy;
a[id<<1].sum1+=a[id<<1].num1*a[id].lazy;
a[id<<1|1].sum1+=a[id<<1|1].num1*a[id].lazy;
a[id<<1].sum2+=(a[id<<1].r-a[id<<1].l+1)*a[id].lazy;
a[id<<1|1].sum2+=(a[id<<1|1].r-a[id<<1|1].l+1)*a[id].lazy;
}
a[id].lazy=0;
}
void pushup(int id){
a[id].num1=a[id<<1].num1+a[id<<1|1].num1;
a[id].sum1=a[id<<1].sum1+a[id<<1|1].sum1;
a[id].sum2=a[id<<1].sum2+a[id<<1|1].sum2;
}
void build(int id,int l,int r){
a[id].l=l,a[id].r=r;
if(l==r){
return ;
}
else{
int mid=l+r>>1;
build(id<<1,l,mid),build(id<<1|1,mid+1,r);
}
}
void modify(int id,int x,int num){ // num 状态
if(a[id].l==a[id].r){
a[id].num1=num;
a[id].sum1=num*a[id].sum2;
}
else{
pushdown(id);
int mid=a[id].l+a[id].r>>1;
if(x<=mid) modify(id<<1,x,num);
else modify(id<<1|1,x,num);
pushup(id);
}
}
void modify(int id,int l,int r,int num){ // num 值
if(a[id].l>=l&&a[id].r<=r){
a[id].sum1+=a[id].num1*num;
a[id].sum2+=(a[id].r-a[id].l+1)*num;
a[id].lazy+=num;
}
else{
pushdown(id);
int mid=a[id].l+a[id].r>>1;
if(r<=mid) modify(id<<1,l,r,num);
else if(l>mid) modify(id<<1|1,l,r,num);
else modify(id<<1,l,r,num),modify(id<<1|1,l,r,num);
pushup(id);
}
}
pair<ll,ll> query(int id,int l,int r){
if(a[id].l>=l&&a[id].r<=r){
return {a[id].num1,a[id].sum1};
}
else{
pushdown(id);
int mid=a[id].l+a[id].r>>1;
if(r<=mid) return query(id<<1,l,r);
else if(l>mid) return query(id<<1|1,l,r);
else{
auto it1=query(id<<1,l,r);
auto it2=query(id<<1|1,l,r);
return {it1.first+it2.first,it1.second+it2.second};
}
}
}
int vis[N];
int main(){
guo312;
cin>>q>>d; build(1,0,200001); ll ans=0;
while(q--){
int x; cin>>x;
if(!vis[x]){
modify(1,x,1);
modify(1,max(1,x-d),x,1);
}
ll va1=0,va2=0,l,r;
r=min(200000,x+d),l=x+1;
if(l<=r){
auto it1=query(1,l,r);
if(it1.first>=2){
va1=it1.first*(it1.first-1)/2;
}
}
r=max(x-1,0),l=max(1,x-d);
if(l<=r){
auto it2=query(1,l,r);
va2=it2.second-it2.first*2;
va2=max((ll)0,va2);
}
if(!vis[x]){
vis[x]=1;
ans+=va1+va2;
cout<<ans<<endl;
}
else{
vis[x]=0;
modify(1,max(1,x-d),x,-1);
modify(1,x,0);
ans-=va1+va2;
cout<<ans<<endl;
}
}
return 0;
}