Leetcode 第 47 场双周赛D 5683. 统计点对的数目(分类讨论、容斥原理,双指针、树的度

2021-03-08 12:21:24 浏览数 (1)

思路:比赛的时候我不知道如何处理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的个数)

代码语言:javascript复制
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.first0000,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;

    }
};

0 人点赞