51Nod-1530 稳定方块(贪心)

1530 稳定方块 

题目来源: CodeForces

基准时间限制:10 秒 空间限制:131072 KB 分值: 80 难度:5级算法题

 收藏

 关注

瓦西亚和皮台亚摆放了m个方块。方块被编号为0到m-1(每个号码出现恰好一次)。现在建立一个座标系OX表示地面,OY的方向是竖直向上的。每一方块的左下角有一个座标而且是整点座标。

摆放好的方块一定要是稳定的。稳定的含意是每一个不在地面上的方块在他的下面至少有一个方块与他相接触。可以是共边,也可以是共点的。也就是说如果方块座标为(x,y),要么y=0,或者存在一个方块的座标为(x-1,y-1)或者 (x,y-1) 或者 (x+1,y-1)。

现在瓦西亚和皮台亚要轮流把这些方块一个个拆下来。按照拆下来的顺序从左到右摆成一行,那么方块上面的编号就会组成一个m进制的数字。

拆的过程中,要始终保持剩下的方块稳定。瓦西亚想要最终的数字尽可能大,而皮台亚想要尽可能小,瓦西亚先开始拆。

请帮助计算一下最终形成的数字是多少,结果比较大,输出对 109+9 取余后的结果。

样例解释:

先拿(0,1)编号为2

再拿(2,1)编号为0

再拿(1,0)编号为1

最后形成的数字是201,转成10进制是19。

 

Input

单组测试数据。
第一行有一个整数 m (2≤m≤10^5)。
接下来m行,每一行有一个方块的座标xi,yi (-10^9≤xi≤10^9, 0≤yi≤10^9),第i个的编号为i。i从0开始。
输入保证刚开始的摆放是稳定的,而且没有两个方块的座标是一样的。

Output

输出结果占一行。

Input示例

样例输入1
3
2 1
1 0
0 1

Output示例

样例输出1
19

题解:搞2个优先队列,一个从大到小排序,一个从小到大,瓦西亚从第一个队列中取,皮台亚从第二个队列中取,数字用完后标记vis不再被第二次使用,需要注意的是,取出一个方块后会对周围的有影响,需要更新周围方块的状态,即有些方块可能会变得不能被取出来,有些方块可能变得可以被取出来了。

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=a-1;i>=b;--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'
#define add(x,y) x=((x)+(y)>=mod)?(x)+(y)-mod:(x)+(y)
#define sub(x,y) x=((x)-(y)<0)?(x)-(y)+mod:(x)-(y)
#define eps 1e-10
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef pair<int, int> PII;

const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MX = 1e5 + 5;
const int mod = 1e9 + 9;


vector<PII>v[MX];
vector<int>vx[MX], vid[MX];
vector<int>up[MX], d[MX];
bool vis[MX], can[MX];
priority_queue<int>q1;
priority_queue<int, vector<int>, greater<int> >q2;
bool check(vector<int>& u) {
    rep(i, 0, u.size()) if(d[u[i]].size() == 1) return 0;
    return 1;
}
void modify1(int x) {
    rep(i, 0, up[x].size()) {
        int y = up[x][i];
        d[y].erase(find(d[y].begin(), d[y].end(), x));
        if(!vis[y] && d[y].size() == 1) can[d[y][0]] = 0;
    }
}
void modify2(int x) {
    rep(i, 0, d[x].size()) {
        int y = d[x][i];
        up[y].erase(find(up[y].begin(), up[y].end(), x));
        if(!vis[y] && check(up[y])) q1.push(y), q2.push(y), can[y] = 1;
    }
}
int main() {
#ifdef local
    freopen("in.txt", "r", stdin);
#endif // local

    int n, x, y, id; cin >> n;
    rep(i, 0, n) {
        cin >> x >> y;
        v[y].push_back(PII(x, i));
    }
    rep(i, 0, n) if(!v[i].empty()) sort(v[i].begin(), v[i].end());
    rep(i, 0, n) rep(j, 0, v[i].size()) vx[i].push_back(v[i][j].x), vid[i].push_back(v[i][j].y);
    rep(i, 0, n) rep(j, 0, v[i].size()) {
        x = v[i][j].x, id = v[i][j].y;
        if(!vx[i + 1].empty()) {
            int l = lower_bound(vx[i + 1].begin(), vx[i + 1].end(), x - 1) - vx[i + 1].begin();
            int r = upper_bound(vx[i + 1].begin(), vx[i + 1].end(), x + 1) - vx[i + 1].begin();
            rep(k, l, r) up[id].push_back(vid[i + 1][k]);
            rep(k, l, r) d[vid[i + 1][k]].push_back(id);
        }
    }
    rep(i, 0, n) if(up[i].empty() || check(up[i])) q1.push(i), q2.push(i), can[i] = 1;
    ll ans = 0;
    rep(i, 0, n) {
        if(i % 2 == 0) {
            while(!q1.empty()) {
                x = q1.top(); q1.pop();
                if(vis[x] || !can[x]) continue;
                vis[x] = 1;
                ans = (ans * n + x) % mod;
                modify1(x);
                modify2(x);
                break;
            }
        } else {
            while(!q2.empty()) {
                x = q2.top(); q2.pop();
                if(vis[x] || !can[x]) continue;
                vis[x] = 1;
                ans = (ans * n + x) % mod;
                modify1(x);
                modify2(x);
                break;
            }
        }
    }
    cout << ans << endl;
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值