思路:比赛的时候我不知道如何处理a、b之间有连边 还有平方级别枚举区间怎么优化
其实可以这样考虑:
可以先跑一遍所有边算各点度,d[x]表示点x的度,然后大体先分两种情况:
1.点对中两个点没有连边
2.点对中两个点有连边,如果有连边,这个很好处理,跑一遍边就好了,要注意重边,所以我们开一个map存,如果直接遍历边集会重复计数(计数d[a]+d[b]-cnt[a,b]>quert[i]) cnt[a,b]是map中该点对出现次数,这里我们做个处理,比如(1,2)、(2,1)都视为同一个点对
对于第一种情况,考虑如下:d[a]+d[b]>quert[i]中分为两种情况一直是cnt[a,b]=0,另一种不为0,那么不为0的求法和第二点类似,d[a]+d[b]>query[i]的求法是双指针就可以统计出来,所以我们就可以间接求出第一种情况的个数(等于双指针统计个数-d[a]+d[b]>quert[i]&&cnt[a,b]=0的个数)
class Solution {
public:
vector<int> countPairs(int n, vector<vector<int>>& e, vector<int>& q) {
int d[20010]={0};
unordered_map<int,int>p,vis,vis1;
for(auto &t:e){
int a=t[0],b=t[1];
d[a]++,d[b]++;
if(a>b)swap(a,b);
p[a*30000+b]++;
}
int test[20010]={0};
memcpy(test,d,sizeof d);
sort(test+1,test+1+n);
vector<int>ans;
for(auto &cnt:q){
int s1=0,s2=0,s3=0;
for(auto &t:p){
int b=t.first%30000,a=t.first/30000;
if(a>b)swap(a,b);
if(d[a]+d[b]>cnt){
s3++;
}
if(d[a]+d[b]-p[a*30000+b]>cnt){
s1++;
}
}
for(int i=n,j=1;i>j;i--){
while(i>j&&test[i]+test[j]<=cnt)j++;
if(i>j&&test[i]+test[j]>cnt)s2+=i-j;
}
ans.emplace_back(s2-s3+s1);
//cout<<s1<<" "<<s2<<" "<<s3<<endl;
}
return ans;
}
};