2023年牛客基础训练营2-K

题目链接:https://ac.nowcoder.com/acm/contest/46810/K

思路:从未见过的科技,根号分治

用这个想法的原因:
本题暴力的主要瓶颈在于对菊花图的花芯的n次访问,最坏复杂度会变成n2级别,所以我们将所有点按照度的多少分类,分类的界限为(val=n),再将所有大于等于这个界限的点建图,查询的时候也分成两类:如果这个点的度数小于val,则直接遍历,否则在新建立的图上遍历。无论哪种情况,遍历的边数一定小于val次,时间复杂度为nn

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
int h[N],ne[N*2],num[N*2],idx;
bool st[N],stt[N];
int cnt[N];
int id[N];
int du[N];
vector<int>g[N];
void add(int x,int y){
    num[idx] = y,ne[idx] = h[x],h[x] = idx++;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n,m,q;
    cin>>n>>m>>q;
    memset(h,-1,sizeof(h));
    for (int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        add(x,y);
        add(y,x);
        du[x]++,du[y]++;
    }
    int val = sqrt(n);
    for (int i=1;i<=n;i++){
        for (int j=h[i];j!=-1;j=ne[j]){
            int e = num[j];
            if (du[i]>=val&&du[e]>=val){
                g[i].push_back(e);
            }
        }
    }
    while(q--){
        int k;
        cin>>k;
        for (int i=1;i<=k;i++) {
            int x;
            cin>>x;
            id[i] = x;
            st[x] = 1;
            if (du[x]>=val) stt[x] = 1;
        }
        int ans = 0;
        for (int i=1;i<=k;i++){
            if (du[id[i]]<val) st[id[i]] = 0;
            else stt[id[i]] = 0; 
            if (du[id[i]]<val){
                for (int j=h[id[i]];j!=-1;j=ne[j]){
                    int v = num[j];
                    if (st[v]) ans++;
                }
            }else{
                for (auto v:g[id[i]]){
                    if (stt[v]) ans++;
                }
            }
        }
        for (int i=1;i<=k;i++){
            st[id[i]] = 0;
        }
        cout<<ans<<'\n';
    }
}
posted @   安潇末痕  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示