题解 | #分组#

分组

https://ac.nowcoder.com/acm/contest/11170/D

D题
因为细节错误,最后一分钟才A出来。。。。。。。

首先,我们有一个很明显的贪心。
就是,我们从左到右去枚举边的话,肯定是尽量囊括边 到濒临阈值的情况下

即,我们从最左端一直向右取边,取到极限,算作一组
然后以当前位置为最左端,向右取边取到极限,算作一组
以此类推。

但是我们是无法这样做的,因为我们无法做到动态的查询强连通分量

那么二分可不可以呢?
首先我们以最左端编号1开始二分,找到他可以取到的最右端的编号l2
然后再次二分。。。。
每次二分都使用一次tajan算法验证一遍

但是这样行不行呢?
没试,但是预计会T 我们可以大致感觉到这个复杂度是有点高的

这时,我看了下数据

然后我们可以意识到一个重要的结论:
如果我这个图中只有n个点,那么这个图的重量一定是<=n^2的!!!!
即,我这些点连成了一个强连通

这个结论扩展到边也差不多
如果这个图有m个边,n个点。那么这个图的重量一定是<=m^2 + n-m !!!!!
即,我m条边构造了一个有m个点的强连通分量,然后剩余n-m个孤立的点!!

一句这个结论我们可以做到什么?
这说明了,我们在一开始就可以按照结论,将整个边序列分成大致 个区间!!!!

然后我们需要考虑的就变成了:
从最左边开始,一个一个地合并区间!
能合并就合并,无法合并就取最右(依照我们之前的贪心策略,我们要尽量包含多的边取到上限!)

而这里,如何找到最右边的那个上限,我们就可以使用二分了!

当然,为了不T我们还需要,稍微修改一下tarjan,中遍历点的情况
即:我们只要保留我们所选区间的点即可。
具体实现见代码:

#include<iostream>
#include<algorithm>
#include<vector>
#include<cmath>
#include<stack>
using namespace std;
typedef long long ll;
const int max_n = 1e6+100;
int n,m;
ll k;
int es[max_n][2];
vector<int> V;
struct edge
{
    int to,next;
}E[max_n<<1];
int head[max_n];
int cnt=1;
void add(int from,int to)
{
    E[cnt].to=to;
    E[cnt].next=head[from];
    head[from]=cnt++;
}

int dfn[max_n],low[max_n];
stack<int> st;
int colour=0;
int color[max_n];
int sz[max_n<<1];
int tot=0;
void tarjan(int u) {
    dfn[u] = low[u] = ++tot;
    st.push(u);
    for (int i = head[u];i;i = E[i].next)
    {
        int v = E[i].to;
        if (!dfn[v]) 
        {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }
        else if (color[v] == 0)low[u] = min(low[u], dfn[v]);
    }
    if (low[u] != dfn[u])return;

    colour++;
    while (st.top() != u) 
    {
        color[st.top()] = colour;
        st.pop();
        sz[colour]++;
    }
    color[st.top()] = colour;
    st.pop();
    sz[colour]++;
}


int que[max_n];
int h=0;
int cct=0;
int vis[max_n];
bool check(int l,int r)
{
    ++cct;
    int nodes = 0;
    h=0;
    for (int i=l;i<=r;++i)
    {
        que[++h]=es[i][0];
        que[++h]=es[i][1];
        if (vis[es[i][0]]!=cct)
        {
            vis[es[i][0]]=cct;
            ++nodes;
        }
        if (vis[es[i][1]]!=cct)
        {
            vis[es[i][1]]=cct;
            ++nodes;
        }
    }
    nodes = n-nodes;
    cnt=1;
    for (int i=1;i<=h;++i)head[que[i]]=dfn[que[i]]=low[que[i]]=color[que[i]]=0;
    for (int i=l;i<=r;++i)add(es[i][0],es[i][1]);

    ll ans = 0;
    tot=0;
    colour=0;
    for (int i=0;i<=h;++i)sz[i]=0;
    while (!st.empty())st.pop();

    for (int i=1;i<=h;++i)
    {
        if (dfn[que[i]])continue;
        tarjan(que[i]);
    }

    for (int i=1;i<=colour;++i)
        ans+= (ll)sz[i]*(ll)sz[i];

    return ans+nodes<=k;
}

int Solve(int cur,int l,int r)
{
//    cout<<cur<<" "<<l<<" "<<r<<endl;
    --r;
    if (check(cur,r))return cur;
    int ans=l-1;
    int lft = l-1,rgt=r;
    while (lft<=rgt)
    {
        int mid = (lft+rgt)>>1;
        if (check(cur,mid))
        {
            lft = mid+1;
            ans = mid;
        }
        else rgt =mid-1;
    }
    ++ans;
    if (ans==r+1)return cur;
    else return ans;
}

int main()
{
    ios::sync_with_stdio(0);
    cin>>n>>m>>k;
    for (int i=1;i<=m;++i)cin>>es[i][0]>>es[i][1];
    V.push_back(1);
    ll lim = sqrt(k);
    while (lim*lim+n-lim>k)--lim;
    for (int i=2;i<=m;++i)
        if (i-V.back()==lim)
            V.push_back(i);

    if (V.size()==1)
    {
        cout<<1<<endl;
        return 0;
    }

    else if (V.size()==2)
    {
        if (check(1,m))cout<<1<<endl;
        else cout<<2<<endl;
        return 0;
    }

    int ans = 1;
    V.push_back(m+1);
    int cur = 1;

    for (int i=1;i<V.size()-1;++i)
    {
        int pre = cur;
        cur = Solve(cur,V[i],V[i+1]);
        if (cur!=pre)++ans;
    }
    cout<<ans<<endl;
}
全部评论

相关推荐

和蔼:在竞争中脱颖而出,厉害! 但是有一个小问题:谁问你了?😡我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了
点赞 评论 收藏
分享
点赞 评论 收藏
分享
希望各位大哥分享一下自己的看法,对于机器人行业确实不太了解
绝顶但不聪明:如果是机器人相关岗位,优先优必选(专门***器人的),其他岗位选小米
投递小米集团等公司10个岗位 > 牛客解忧铺 牛客在线求职答疑中心
点赞 评论 收藏
分享
6 收藏 评论
分享
牛客网
牛客企业服务