noi.ac #535 生成树

题目链接:戳我


我们考虑按照编号依次加点,然后维护一个栈。
预设生成树的颜色为color。
对于当前点x,如果它和栈首的点连边颜色相同,那么他们的连边可以作为生成树上面的边,点i已经连接,直接break掉即可。
如果和栈首的点连边颜色和预设颜色不同,那么这条边是不能连的,弹栈。但是前面的点已经构成了生成树,所以我们看一看能不能和前面栈里的点连起来,如果可以的话,自然是把这个边放到生成树的边里就星了。如果一直弹到栈空都没有找到的话,相当于这个点可以和前面的所有点都连上另外一种颜色的边,我们直接把颜色翻转一下就可以了qwq。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<stack>
#define MAXN 500010
#define ll long long
#define mp make_pair
using namespace std;
int n,m;
ll X,Y,Z,P[MAXN];
map<int,int>c[MAXN];
inline int query(int x,int y)
{
    if(c[x].count(y)) return c[x][y];
    if((X*min(x,y)+Y*max(x,y))%Z<P[x]+P[y]) return 0;
    return 1;
}
inline void solve()
{
    vector<pair<int,int> >g[2];
    stack<int>q;
    q.push(1);
    int color=0;
    for(int i=2;i<=n;i++)
    {
        while(!q.empty())
        {
            int x=q.top();
            int c=query(x,i);
            g[c].push_back(mp(x,i));
            if(c!=color) q.pop();
            else break;
        }
        if(q.empty()) color^=1,q.push(1);
        q.push(i);
    }
    if(g[color].size()!=n-1) printf("No solution");
    else
    {
        for(int i=0;i<g[color].size();i++)
            printf("%d %d
",g[color][i].first,g[color][i].second);
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        c[x][y]=c[y][x]=z;
    }
    scanf("%lld%lld%lld",&X,&Y,&Z);
    for(int i=1;i<=n;i++) scanf("%lld",&P[i]);
    solve();
    return 0;
}
原文地址:https://www.cnblogs.com/fengxunling/p/11144029.html