Digi Comp II UVALive - 6953 (bfs/拓扑)

Uva https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4965

vjudge https://vjudge.net/problem/UVALive-6953


雾草 一波瞎优化从2000ms跑到800ms.....


题意:给你n(1~10^18)个球 m个点 每个点有一个状态 一个球来过状态就改变 根据当前状态确定下一步(状态左右)

输入 m行 : 初始状态 左子树 右子树

直接模拟会超时

利用拓扑思想 记录入度 然后队列模拟

首先几点必须注意

1.落下偶数小球 状态不变

2.落下奇数小球 状态改变

3.左右子树 可以相同(左右子树描述不确切)

4.入度为零的点可能不只是1节点

详见下代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <map>

using namespace std;

#define sf scanf
#define pf printf
#define ll long long
#define For(i,a,b) for(i=a;i<=b;i++)
#define _For(i,a,b) for(i=b;i>=a;i--)
#define Out(x) cout<<x<<endl
#define Outdouble(x,a) cout<<fixed<<setprecision(a)<<1.0*x<<endl
#define mset(arr,num) memset(arr,num,sizeof(arr))
#define ok std::ios::sync_with_stdio(0)
#pragma comment(linker, "/STACK:102400000,102400000")
#pragma GCC optimize("O3")

const ll inf = 1e12+10;  ///
const double esp = 1e-7; ///
const int NUM = 1e5+10;

// #define debug
#if defined (debug)
---check---
#endif

/// ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^  ^_^ ///

struct node
{
    ll num;
    int dis;  ///1表示Left  0表示Right
    int l,r;
} arr[5*NUM];

int indeg[5*NUM]; ///存入度
ll n,m; ///long long 把我卡炸了

void bfs()
{
    int i,past;
    queue <int> q;
    For(i,1,m)  ///注意 如果某点入度为零也要加进来 因为关系到后面节点的入度--问题
    {
        if(indeg[i]==0)
        {
            q.push(i);
        }
    }
    while(!q.empty())
    {
        past = q.front();
        q.pop();

        int L = arr[past].l;
        int R = arr[past].r;

        arr[L].num+=arr[past].num>>1;
        arr[R].num+=arr[past].num>>1;

        if((arr[past].num&1) == 1) ///如果小球是奇数那么多出来的一个判断分给谁
        {
            if(arr[past].dis == 1) ///根据父节点来判断当前状态
            {
                arr[L].num++;
            }
            else
            {
                arr[R].num++;
            }
            arr[past].dis^=1; ///转换状态
        }                     ///当落上珠子和是偶数那么并不会变状态

        arr[past].num = 0;
        indeg[L]--;
        indeg[R]--;  ///入度减一 父节点"释放"

        if(L!=0 && indeg[L]==0)  ///只要不为零,入度为零 那么前面就没有球落进来了 状态就固定了
        {
            q.push(L);
            if(L == R) continue; ///左右孩子相同的情况 记得判断
        }
        if(R!=0 && indeg[R]==0)
        {
            q.push(R);
        }
    }
}

void Output()
{
    int i;
    For(i,1,m)
    {
        if(arr[i].dis == 1)
        {
            pf("L");
        }
        else pf("R");
    }
    pf("\n");
}

int main()
{
    ok;
    char s[5];
    int i,j;
    while(cin>>n>>m)
    {
        mset(indeg,0);
        mset(arr,0);

        For(i,1,m)
        {
            cin>>s>>arr[i].l>>arr[i].r;
            indeg[arr[i].l]++;
            indeg[arr[i].r]++;  ///记录入度

            if(s[0] == 'L')
            {
                arr[i].dis = 1;
            }
            else arr[i].dis = 0;
        }
        arr[1].num = n;  ///n个球放在1上
        bfs();
        Output();
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值