题意:
有n个人,一开始所有人互相不认识。
现在有m场party,每场给出L,R,表示编号在[L,R]内的所有人参加,参加之后这些人互相认识。
现在要求计算每次party之后会有多少对新的互相认识的人,
数据范围:n,m<=2e5
解法:
因为区间是连续的,
令L[i]表示第i个人向左方向认识的最大位置(不需要R[i],i会被满足i<j的L[j]覆盖到),
给定查询[l,r],问题可以变为计算
∑
i
=
l
r
[
L
[
i
]
>
l
]
∗
(
L
[
i
]
−
l
)
,
然
后
更
新
L
[
i
]
为
l
\sum_{i=l}^r[L[i]>l]*(L[i]-l),然后更新L[i]为l
∑i=lr[L[i]>l]∗(L[i]−l),然后更新L[i]为l。
显然需要区间取min操作,同时需要维护一个区间max,可以上吉司机线段树。
因为每次修改都需要修改的叶子节点,可以在更新的同时统计答案。
吉司机线段树的复杂度应该是O(mlogn)的。
code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxm=5e5+5;
int n,m;
struct Tree{
int a[maxm<<2];
void pp(int node){
a[node]=max(a[node*2],a[node*2+1]);
}
void build(int l,int r,int node){
if(l==r){
a[node]=l;
return ;
}
int mid=(l+r)/2;
build(l,mid,node*2);
build(mid+1,r,node*2+1);
pp(node);
}
ll update(int st,int ed,int val,int l,int r,int node){
if(a[node]<=val)return 0;
if(l==r){
ll ans=a[node]-val;
a[node]=val;
return ans;
}
int mid=(l+r)/2;
ll ans=0;
if(st<=mid)ans+=update(st,ed,val,l,mid,node*2);
if(ed>mid)ans+=update(st,ed,val,mid+1,r,node*2+1);
pp(node);
return ans;
}
}T;
signed main(){
while(scanf("%d%d",&n,&m)!=EOF){
T.build(1,n,1);
while(m--){
int l,r;scanf("%d%d",&l,&r);
ll ans=T.update(l,r,l,1,n,1);
printf("%lld\n",ans);
}
}
return 0;
}