给定一个长度为 n 的整数数列 a1,a2,…,an 和一个整数 t。
请你判断共有多少个数对 (l,r) 同时满足:
- 1≤l≤r≤n
- al+al+1+…+ar−1+ar<t
输入格式
第一行包含两个整数 n 和 t。
第二行包含 n 个整数 a1,a2,…,an。
输出格式
一个整数,表示满足条件的数对的数量。
数据范围
前三个测试点满足 1≤n≤5。
所有测试点满足 1≤n≤2×105,|t|≤2×1014,|ai|≤109。
输入样例1:
5 4
5 -1 3 4 -1
输出样例1:
5
输入样例2:
3 0
-1 2 -3
输出样例2:
4
输入样例3:
4 -1
-2 1 -2 3
输出样例3:
3
分析:
这道题用到了树状数组的思想,由题可知 s[r]-t<s[l-1]
在值域上维护一个树状数组,维护每个前面的前缀和数值的个数的和,枚举每个右端点r,每次将答案累加上树状数组中大于sumr−t的总个数,然后再给 sumr 这个位置的个数加上1,方便后续的计算。
由于值域很大很大,树状数组开不下,所以我们要先将前缀和数组离散化
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int fa[2*N],x1[N],x2[N],e[N];
vector<int>an,a1;
int t,n;
int find(int x)
{
if(fa[x]!=x) fa[x]=find(fa[x]);
//cout<<x<<" x "<<fa[x]<<endl;
return fa[x];
}
int findid(int x)
{
return lower_bound(a1.begin(),a1.end(), x)-a1.begin()+1;
}
int main()
{
cin>>t;
while(t--)
{
cin>>n;
int flag=1;
an.clear(),a1.clear();
for(int i=1;i<=n;i++)
{
cin>>x1[i]>>x2[i]>>e[i];
an.push_back(x1[i]);
an.push_back(x2[i]);
}
sort(an.begin(),an.end());
for(int i=0;i<2*n;i++)
{
if(i&&an[i]==an[i-1])continue;
else a1.push_back(an[i]);
}
for(int i=1;i<=an.size();i++)fa[i]=i;
for(int i=1;i<=n;i++)
{
if(!e[i]) continue;
int xx=find(findid(x1[i]));
int yy=find(findid(x2[i]));
fa[xx]=yy;
}
for(int i=1;i<=n;i++)
{
if(e[i])continue;
int xx=find(findid(x1[i]));
int yy=find(findid(x2[i]));
if(xx==yy)
{
flag=0;
break;
}
}
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}