1.首先明确这道题想要求取的是在l-r中新认识的人的对数
如果想要知道新认识的人是多少,那么我们可能会考虑到上次认识的人的左右边界。并且可以想象到的是,在一个区间中,右边的人新认识的左边的人,其实就是左边的人新认识的右边的人
如果重复的计算,那么最后要/2。所以我们可以直接考虑有边界
2.有一个性质可以通过观察得到,也就是越往右的人的右边界一定大于等于左边的右边界,因为每次都是连续的一段区间,左边的人不可能绕过右边的人去认识更右边的人。所以这个维护的值是递增的
那么每次新认识的人其实就是找到最右边的一个有边界小于r的点pos,答案就是(r-l+1)*r-从l-pos的r相加,也就是前面一段中每个离右边界的人数之和
这样就发现了一个区间求和操作,之后我们要更改掉现有的有边界,也就是将l-pos这段的有边界都设置为r,这里有个区间修改操作。同时还需要一个函数来计算pos的位置
这样就能看出线段树非常擅长这些
对于区间问题,需要仔细想可以接受复杂度内的一些性质。以后还要多多锻炼,这个是向网上博客大佬学习后才发现的做法。
#include<iostream> #include<cstring> #include<cstdio> #include<map> #include<algorithm> #include<queue> #define ull unsigned long long using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=5e5+10; struct node{ int l,r; ll sign; ll lazy; ll sum; }tr[N<<2]; void pushup(int u){ tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;//边界的r和 tr[u].sign=tr[u<<1|1].sign;//最右边界的更新,肯定是由右边更新而来 } void build(int u,int l,int r){ if(l==r){ tr[u]=node{l,r,l,0,l}; } else{ int mid=l+r>>1; tr[u]={l,r}; build(u<<1,l,mid); build(u<<1|1,mid+1,r); pushup(u); } } void pushdown(int u){ tr[u<<1].lazy=tr[u<<1|1].lazy=tr[u].lazy; tr[u<<1].sign=tr[u<<1|1].sign=tr[u].lazy; tr[u<<1].sum=(tr[u<<1].r-tr[u<<1].l+1)*tr[u].lazy; tr[u<<1|1].sum=(tr[u<<1|1].r-tr[u<<1|1].l+1)*tr[u].lazy; tr[u].lazy=0; } void modify(int u,int l,int r,ll x){ if(tr[u].l>=l&&tr[u].r<=r){ tr[u].sign=x; tr[u].lazy=x; tr[u].sum=(tr[u].r-tr[u].l+1)*x;//对于范围内直接修改 return ; } if(tr[u].lazy!=0) pushdown(u); int mid=tr[u].r+tr[u].l>>1; if(l<=mid) modify(u<<1,l,r,x); if(r>mid) modify(u<<1|1,l,r,x); pushup(u); } int querypos(int u,int x){ if(tr[u].l==tr[u].r){ if(tr[u].sign<=x) return tr[u].l; else return -1;//可能就没有满足条件的 } if(tr[u].lazy) pushdown(u); if(tr[u<<1].sign<=x) //当左边满足条件,就要对两边的取max return max((int)tr[u<<1].r,querypos(u<<1|1,x)); else{ return querypos(u<<1,x);//不然就在左边 } } ll query(int u,int l,int r){ if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum; int mid=tr[u].l+tr[u].r>>1; if(tr[u].lazy) pushdown(u); ll ans=0; if(l<=mid) ans=query(u<<1,l,r); if(r>mid) ans+=query(u<<1|1,l,r); return ans; } int main(){ int n,m; while(cin>>n>>m){ build(1,1,n); while(m--){ int l,r; scanf("%d%d",&l,&r); ll ans=0; int pos=querypos(1,r); if(pos<l) ans=0; else{ ans=(ll)(pos-l+1)*r-query(1,l,pos); modify(1,l,pos,r); } printf("%lld ",ans); } } }