ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces 1548E Gregor and the Two Painters

2021-12-04 20:03:48  阅读:230  来源: 互联网

标签:int na Gregor Codeforces pos Painters sc mx define


题目链接

Codeforces 1548E Gregor and the Two Painters

题目大意

有两个序列 \(\{a\}\) 和 \(\{b\}\),长度分别为 \(n\) 和 \(m\),由此构造 \(n\times m\) 的网格,\((i,j)\) 处的权值为 \(a_i+b_j\),称格子 \((i,j)\) 是坏的若格子的权值 \(\leq X\)。求图中坏格子的连通块数量。

\(1\leq n,m,a_i,b_i,X\leq 2\times 10^5\)

思路

思维性相当强的有趣题。

\(2e5\times2e5\) 的网格非常大,同时容易构造出答案为 \(\frac{nm}{4}\) 的数据,不可能用并查集之类的东西去维护,于是东碰西撞研究单调性包含性想不出来被迫去看 Hint 后能发现这样一个思路,我们尝试给每个连通块选出一个标记点,这样只需要快速统计标记点的个数即可。

通过形状属性来选标记点是困难的,因为连通块的形状几乎是任意的,很难快速确定点是否满足要求,于是通过点自身属性来选,容易想到挑权值最小的。对于最小的点,连通块其它部分都比它大,而不是坏的格子显然也比它大,那么我们在连通块周围框一个矩形出来(外切),可以证明,标记点即矩形内最小的点,这个命题等价于矩形中不会存在别的坏格子连通块,但是注意到对于网格中的相邻两行,他们拥有的坏格子集合必然是包含的关系(单调性),而若存在别的连通块便会违反这个性质,出现这边连不上,而本应是被包含的地方反而连上的情况。

从而标记点 \((i,j)\) 的 \(a_i\) 和 \(b_i\) 都是矩形对应区间里的最小值,所以要判定一个点是否是标记点,只需要分别看在横向和纵向上,第一个权值比其小的格子是否和它在一个连通块里即可,然后再根据行行(以及列列)之间的包含性,可以再将其简化为:到比其小的格子之间的一条上,是否有权值 \(>X\) 的格子。

有了这个性质,便可以着手开始统计了。对于 \(\{a\}\) 序列,用单调栈维护出 \(a_i\) 往左往右遇到的第一个 \(<a_i\) 的位置,记为 \(l_i,r_i\),然后记 \(na_i=\min(\max_{i\in[l_i,i-1]}\{a_i\},\max_{i\in[i+1,r_i]}\{a_i\})\),表示若第 \(i\) 行的点要成为非标记点,则这个连通块需要包含 \(a_j=na_i\) 的行,\(na_i\) 可以在单调栈时顺带维护出,类似地处理出 \(nb_i\)。现在可以得到,一个点为标记点,当且仅当:

  • \(a_i+b_j\leq X\)
  • \(a_i+nb_j>X\)
  • \(na_i+b_j>X\)

这是一个简洁的偏序问题!对于后两个限制,只需要求 \(a_i+nb_i,\;na_i+b_i\) 中较小的 \(>X\) ,移一下项,检查 \(na_i-a_i,\;nb_i-b_i\) 较大的那个对应的式子即可。于是我们维护两棵树状数组 \(T_a,T_b\),将 \((na_i-a_i,a_i)\) 和 \((nb_i-b_i,b_i)\) 二元组一起从大到小处理,若当前是 \((na_i-a_i,a_i)\),便将答案加上 \(T_b\) 中 \((X-na_i,X-a_i]\) 的权值,然后 \(T_a\) 中 \(a_i\) 的位置加 \(1\),\((nb_i-b_i,b_i)\) 类似。

时间复杂度 \(O(n\log n)\)

Code

#include<iostream>
#include<stack>
#include<algorithm>
#include<vector>
#define rep(i,a,b) for(int i = (a); i <= (b); i++)
#define per(i,b,a) for(int i = (b); i >= (a); i--)
#define N 200021
#define PII pair<int, int>
#define PIP pair<int, PII>
#define fr first
#define sc second
#define lowbit(x) (x&-x)
#define ll long long
#define Inf 0x3f3f3f3f
using namespace std;

int n, m, x;
int a[N], b[N];
int l[N], r[N], na[N], nb[N];
stack<PII> s;
vector<PIP> vec;

struct Fenwick{
    int t[N];
    void update(int pos, int k){
        while(pos < N) t[pos] += k, pos += lowbit(pos);
    }
    int get(int pos){
        int ret = 0;
        while(pos) ret += t[pos], pos -= lowbit(pos);
        return ret;
    }
} T[2];

void prework(int n, int *a, int *na){
    a[0] = a[n+1] = x+1;
    s.push({0, x+1});
    rep(i,1,n){
        int mx = a[i];
        while(!s.empty() && a[s.top().fr] >= a[i]) mx = max(mx, s.top().sc), s.pop();
        l[i] = mx, s.push({i, mx});
    }
    while(!s.empty()) s.pop();
    s.push({n+1, x+1});
    per(i,n,1){
        int mx = a[i];
        while(!s.empty() && a[s.top().fr] > a[i]) mx = max(mx, s.top().sc), s.pop();
        r[i] = mx, s.push({i, mx});
    }
    while(!s.empty()) s.pop();
    rep(i,1,n) na[i] = min(l[i], r[i]);
}

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m>>x;
    rep(i,1,n) cin>>a[i];
    rep(i,1,m) cin>>b[i];

    prework(n, a, na), prework(m, b, nb);
    ll ans = 0;
    rep(i,1,n) vec.push_back({na[i]-a[i], {a[i], 0}});
    rep(i,1,m) vec.push_back({nb[i]-b[i], {b[i], 1}});
    sort(vec.begin(), vec.end());
    reverse(vec.begin(), vec.end());
    for(PIP p : vec){
        ans += T[p.sc.sc^1].get(max(x-p.sc.fr, 0)) - T[p.sc.sc^1].get(max(x - (p.fr+p.sc.fr), 0));
        T[p.sc.sc].update(p.sc.fr, 1);
    }
    cout<< ans <<endl;
    return 0;
}

标签:int,na,Gregor,Codeforces,pos,Painters,sc,mx,define
来源: https://www.cnblogs.com/Neal-lee/p/15643032.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有