F. Greetings
读题
所有人的速度相同,也就是说,如果大家都在动,那么大家永不相交。所以相交的情况有且仅有b到终点了,而a还在b的后面,且a的终点在b的后面
将上述情况模型化后,就是求每个人行动的区间包含了多少人,然后对每个人求和
题解
再度简化,对于第\(i\)人来说,就是求\(r\)小于它且\(l\)大于它的人数
我们可以这样想,对r进行升序排序,然后遍历,这个时候\(i-1\)所代表的是\(r\)小于其的人数,然后怎么求r小于它的人里l大于它的呢?
天才的想法:反过来求,利用前缀和,找出l小于它的人数,然后相减就是答案。前缀和用树状数组快速求解
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct node
{
ll l;
ll r;
friend bool operator <(node a,node b){return a.r<b.r;}
}edge[200005];
ll l[200005]={0};
ll pres[200005]={0};
ll n;
ll lowbit(ll x)
{
return x & -x;
}
void occur(ll x)
{
for(ll i=x;i<=n;i+=lowbit(i))pres[i]++;
}
ll inquire(ll x)
{
ll cnt=0;
for(ll i=x;i>=1;i-=lowbit(i))cnt+=pres[i];
return cnt;
}
int main()
{
ios_base::sync_with_stdio(false);
ll t;
cin>>t;
while(t--)
{
memset(pres,0,sizeof(pres));
cin>>n;
for(ll i=1;i<=n;i++)
{
cin>>l[i];
cin>>edge[i].r;
edge[i].l=l[i];
}
sort(l+1,l+n+1);
sort(edge+1,edge+1+n);
ll ans=0;
for(ll i=1;i<=n;i++)
{
ll pos=lower_bound(l+1,l+1+n,edge[i].l)-l;
ll pre=inquire(pos);
ans+=i-1-pre;
occur(pos);
}
cout<<ans<<endl;
}
return 0;
}

浙公网安备 33010602011771号