CSA Round #84 The Sprawl

题目

Analysis

曼哈顿距离($L1$ metric)最小生成树。

Implementation

下面的代码参考了 gispzjz 在比赛中的提交

#include <bits/stdc++.h>

using namespace std;
#define pb push_back
#define eb emplace_back
#define all(x) x.begin(), x.end()
#define debug(x) cerr << #x <<": " << (x) << endl
#define DEBUG printf("Passing [%s] in LINE %d\n",__FUNCTION__,__LINE__)
#ifdef LOCAL
#define see(x) cout  << #x << ": " << (x) << endl
#endif
#ifndef LOCAL
#define see(x)
#endif


#define rep(n) for(int _ = 0; _ != (n); ++_)
//#define rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define Rng(i, n) for(int i = 0; i != (n); ++i)
#define rng(i, a, b) for(int i = (a); i < (b); ++i)
#define rno(i, b) for(int i = 0; i<(b); ++i)
#define rnc(i, a, b) for(int i = (a); i<=(b); ++i)
#define RNG(i, a) for(auto &i: (a))
#define dwn(i, r, l) for(int i = (r); i>=(l); i--)

namespace std {
    template<class T>
    T begin(std::pair<T, T> p)
    {
        return p.first;
    }
    template<class T>
    T end(std::pair<T, T> p)
    {
        return p.second;
    }
}


#if __cplusplus < 201402L
template<class Iterator>
std::reverse_iterator<Iterator> make_reverse_iterator(Iterator it)
{
    return std::reverse_iterator<Iterator>(it);
}
#endif

template<class Range>
std::pair<std::reverse_iterator<decltype(begin(std::declval<Range>()))>, std::reverse_iterator<decltype(begin(std::declval<Range>()))>> make_reverse_range(Range &&r)
{
    return std::make_pair(make_reverse_iterator(::begin(r)), make_reverse_iterator(::end(r)));
}

#define RRNG(x, cont) for (auto &x: make_reverse_range(cont))



template<class T> int sign(const T &a) { return a == 0 ? 0 : a > 0 ? 1 : -1; }
template<class T> inline T min(T a, T b, T c){return min(min(a, b), c);}
template<class T> inline T max(T a, T b, T c){return max(max(a, b), c);}
template<class T> void Min(T &a, const T &b){ a = min(a, b); }
template<class T> void Max(T &a, const T &b){ a = max(a, b); }

template<typename T> void println(const T &t) { cout << t << '\n'; }
template<typename T, typename ...Args> void println(const T &t, const Args &...rest) { cout << t << ' '; println(rest...); }

template<typename T> void print(const T &t) { cout << t << ' '; }

template<typename T, typename ...Args> void print(const T &t, const Args &...rest) { cout << t; print(rest...); }

// this overload is chosen when there's only one argument
template<class T> void scan(T &t) { cin >> t; }
template<class T, class ...Args> void scan(T &a, Args &...rest) { cin >> a; scan(rest...); }

using ll = long long;
using ull = unsigned long long;
using vec = vector<ll>;
using mat = vector<vec>;
using pii = pair<int, int>;
using pdd = pair<double, double>;
using pip = pair<int, pii>;
using szt = size_t;
using vi = vector<int>;
using vl = vector<ll>;
using vb = vector<bool>;
using vpii = vector<pii>;
using vvi = vector<vi>;
using pli = pair<ll,int>;
using wg = vector<vpii>; //weighted graph

int cas;
const double pi = acos(-1);
ll mod = 1e9 + 7;
//要求:0<=a<mod, 0<=b<=mod
template<class T>
inline void add_mod(T &a, const T &b) {
    a += b;
    if (a >= mod) a -= mod;
}
template<class T>
void sub_mod(T &a, const T &b){
    a -= b;
    if (a < 0) a += mod;
}
auto bo=[](int x){
    bitset<5> a(x);
    cout << a << endl;
};

//返回值:a中比k小的元素有多少个?
template<class V, class Cont>
int get_rank(const V &k, const Cont &a){
    return std::lower_bound(all(a), k) - a.begin();
}

mat operator*(const mat &a, const mat &b) {
    mat c(a.size(), vec(b[0].size()));
    for (size_t i = 0; i < a.size(); i++) {
        for (size_t j = 0; j < a[0].size(); j++) {
            if (a[i][j]) { // optimization for sparse matrix
                for (size_t k = 0; k < b[0].size(); k++) {
                    add_mod(c[i][k], a[i][j] * b[j][k] % mod);
                }
            }
        }
    }
    return c;
}

vec operator*(const mat &a, const vec &b) {
    vec c(a.size());
    for (size_t i = 0; i < a.size(); i++) {
        for (size_t j = 0; j < a[0].size(); j++) {
            add_mod(c[i], a[i][j] * b[j] % mod);
        }
    }
    return c;
}

mat pow(mat a, ull n) {
    mat res(a.size(), vec(a[0].size()));
    for (size_t i = 0; i < a.size(); i++) {
        res[i][i] = 1;
    }
    while (n) {
        if (n & 1) {
            res = res * a;
        }
        a = a * a;
        n >>= 1;
    }
    return res;
}

// Codeforces does not support __int128
//std::ostream& operator<<(std::ostream& os, __int128 T) {
//    if (T<0) os<<"-";
//    if (T>=10 ) os<<T/10;
//    if (T<=-10) os<<(-(T/10));
//    return os<<( (int) (T%10) >0 ? (int) (T%10) : -(int) (T%10) ) ;
//}
//
//__int128 LPOW(__int128 x, ll n) {
//    __int128 res = 1;
//    for (; n; n /= 2, x *= x, x %= mod) {
//        if (n & 1) {
//            res *= x;
//            res %= mod;
//        }
//    }
//    return res;
//}

ll POW(ll x, ll n){
    ll res = 1;
    for (; n; n /= 2, x *= x, x %= mod) {
        if (n & 1) {
            res *= x;
            res %= mod;
        }
    }
    return res;
}


ll INV(ll x) {
    return POW(x, mod - 2);
}

ll inv(ll x){
//    see(x);
    return x == 1? 1: (mod - mod/x * inv(mod%x) % mod);
}



// 2D rotation
void rotate(double &x, double &y, double theta) {
    double tx = cos(theta) * x - sin(theta) * y;
    double ty = sin(theta) * x + cos(theta) * y;
    x = tx, y = ty;
}

struct dsu{
    vector<int> par;
    explicit dsu(int n){ // 0-indexed
        par.resize(n);
        rng(i, 0, n){
            par[i] = i;
        }
    }
    bool same(int x, int y){
        return root(x) == root(y);
    }
    int root(int x){
        return par[x] == x ? x : par[x] = root(par[x]);
    }
    void unite(int x, int y){
        x = root(x);
        y = root(y);
        par[x] = y;
    }
};

struct bit {
    vector<int> a;
    vector<int> id; // id[i]:键区间(i-lowbit(i), i]中,x+y取最小值的点的编号
    bit(int n, int v = 0, bool manhattan = false) {
        a.resize(n + 1);
        for (int i = 1; i <= n; ++i) a[i] = v;
        if(manhattan){
            id.resize(n+1);
            rng(i, 1, n+1) id[i] = -1;
        }
    }

    ll sum(int x) {
        ll res = 0;
        while (x) {
            res += a[x];
            x -= x & -x;
        }
        return res;
    }

    ll sum(int l, int r) {
        if (l > r) return 0;
        return sum(r) - sum(l - 1);
    }

    void add(int x, ll v) {
        while (x < a.size()) {
            a[x] += v;
            x += x & -x;
        }
    }

    void min(int x, int v) {
        while (x < a.size()) {
            a[x] = std::min(a[x], v);
            x += x & -x;
        }
    }

    int manhattan_min(int x){ // 返回x+y最小的点的编号
        int ans = -1;
        int res = INT_MAX;
        while(x){
            if(a[x] < res){
                res = a[x];
                ans = id[x];
            }
            x -= x & - x;
        }
        return ans;
    }

    void manhattan_min(int x, int v, int i){
        while(x < a.size()){
            if(a[x] > v){
                a[x] = v;
                id[x] = i;
            }
            x += x & - x;
        }
    }


    void max(int x, int v) {
        while (x < a.size()) {
            a[x] = std::max(a[x], v);
            x += x & -x;
        }
    }

    int min(int x) {
        int res = INT_MAX;
        while (x) {
            res = std::min(res, a[x]);
            x -= x & -x;
        }
        return res;
    }

    int max(int x) {
        int res = INT_MIN;
        while (x) {
            res = std::max(res, a[x]);
            x -= x & -x;
        }
        return res;
    }
};


namespace util{
    int len(ll x){return snprintf(nullptr, 0, "%lld", x);}
    vi get_d(ll x){
        vi res;
        while(x) {
            res.pb(x%10);
            x /= 10;
        }
        reverse(all(res));
        return res;
    }
    template <class T> T parity(const T &a){
        return a & 1;
    }
    template <class T>
    void out (const vector<T> &a){
        std::copy(a.begin(), a.end(), std::ostream_iterator<T>(std::cout, ", "));
        cout << endl;
    };
}

using namespace util;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>


using order_statistic_tree = __gnu_pbds::tree<
        int,
        __gnu_pbds::null_type,
        greater<int>,
        __gnu_pbds::rb_tree_tag,
        __gnu_pbds::tree_order_statistics_node_update>;


const ll LINF = LLONG_MAX/10;
const int INF = INT_MAX/10;
const int M = 5005;


const int N = 1e5+5;

int a[N];

struct point{
    int x, y, id;
    bool operator<(const point &rhs)const{
        return x < rhs.x || (x == rhs.x && y < rhs.y);
    }
    int dis(const point rhs) {
        return abs(x - rhs.x) + abs(y - rhs.y);
    };
};

struct edge{
    int u, v, l;
    bool operator<(const edge &rhs) {
        return l < rhs.l;
    };
};

ll kruskal(vector<edge> &e, int n) { // 0-indexed
    dsu a(n);
    vi size(n);
    fill(all(size), 1);

    sort(all(e));

    ll sum = 0;
    int cnt = 0;
    RNG(x, e) {
        int u = a.root(x.u), v = a.root(x.v);
        if(u != v){
            sum += 1LL * x.l/2 * size[u] * size[v];
            a.par[u] = v;
            size[v] += size[u];
            ++cnt;
            if(cnt == n - 1) break;
        }
    }
    return sum;
};

void R1(vector<point>& a, vector<edge> &e){
    // 离散化
    map<int, int> ls;

    RNG(p, a) {
        ls[p.x - p.y];
    }

    int cnt = 0;

    RNG(x, ls) {
        x.second = ++cnt;
    }


    bit b(cnt, INT_MAX, true);

    sort(all(a));


    dwn(i, a.size() - 1, 0) {
        // 为了好写,规定区域 R_1(s) 为 x >= x_s, x - y <= x_s - y_s
        int pos = ls[a[i].x- a[i].y];
        int j = b.manhattan_min(pos);
        if (j != -1) {
            e.pb({a[i].id, a[j].id, a[i].dis(a[j])});
        }
        b.manhattan_min(pos, a[i].x + a[i].y, i);
    }
}

ll manhattan(vector<point> &a){
   vector<edge> e;
   rng(i, 0, 4){
       if(i == 1 || i == 3){ // 交换x,y坐标
           RNG(j, a){
               swap(j.x, j.y);
           }
       }
       else if(i == 2){
           RNG(j, a){
               j.x = - j.x;
           }
       }
       R1(a, e);
   }

   return kruskal(e, a.size());
}

int main() {
    // Single Cut of Failure taught me
    cout << std::fixed;
    cout << setprecision(10);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);


#ifdef LOCAL
    freopen("main.in", "r", stdin);
//    freopen("main.out", "w", stdout);
#endif

    int n;
    scan(n);
    vector<point> p(n);

    rng(i, 0, n){
        scan(p[i].x, p[i].y);
        p[i].id = i;
    }

    println(manhattan(p));

#ifdef LOCAL
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

备忘

$R_1(s)\colon x \ge x_s, x - y \le x_s - y_s$,
$R_2(s)\colon y \ge y_s, x - y \ge x_s - y_s$,
$R_3(s) \colon y \le y_s, x + y \ge x_s + y_s$,
$R_4(s) \colon x \ge x_s, x+y \le x_s + y_s $ 。

$R_2$ 变换到 $R_1$: $(x,y) \to (y, x)$
$R_3$ 变换的 $R_1$: $(x, y) \to (-y, x)$
$R_4$ 变换到 $R_1$:$(x, y) \to (x, -y)$

$R_1, R_2$ 的离散化部分可共用, $R_3, R_4$ 的离散化部分可共用,但上面给出的实现并未这样做,这是一个可以优化的点。

扩展

欧几里得距离最小生成树也可用类似的划分平面的方法解决。
仍然可以按 $45^\circ$ 度划分平面。$\forall a, b \in R_1(s)$,在 $\triangle sab$ 中,有 $\angle{s} < \max(\angle{a}, \angle{b})$,于是由正弦定理可知 $|ab| < \max(|sa|,|sb|)$ 。

转载于:https://www.cnblogs.com/Patt/p/9369120.html

Shifts in China’s Rural and Urban Population: 2000-2020 The bar chart clearly reveals that from 2000 to 2020, while the total population in China increased moderately from 1.25 billion to 1.41 billion, population in urban and rural areas experienced dramatic shifts in different directions. Urban population rose from 450 million in 2000 to 670 million in 2010 and 900 million in 2020; contrastingly, rural population declined from 800 million in 2000 to 680 million in 2010 and 510 million in 2020. The population gap narrowed largely because of the joint effects of urbanization, unequal economic opportunities in rural and urban areas, and the expansion of higher education. In the first place, there was a large-scale urban sprawl during this period. Places which had been part of the vast countryside were incorporated into cities, causing hundreds of millions of rural dwellers to be passively transformed into urban residents. What’s more, while urban living standards improved greatly in these years, few economic opportunities fell on rural areas and most peasant families remained at the poverty line. Poverty prompted the call for change, leading a large quantity of healthy young peasants to leave their hometowns and flock to cities for a better living. Last but not least, China’s higher education grew at an unprecedented rate in these years. More high school graduates than ever before entered colleges and universities, most of whom preferred to stay in urban areas after graduation for personal development. The increase in urban population was a sure indication of economic and educational achievements in China. It benefited the country in many aspects, relieving the shortage of labor force in cities, lessening the burden of peasants to support their families, and affording young people from rural areas more opportunities to display their talents. However, the migration of rural residents into urban areas inevitably brought about disadvantages. Some of them, such as waste of arable land and left-behind children in the countryside, as well as traffic congestion and soaring housing prices in cities, have already called the attention of the government and corresponding measures have begun to take effect. But others, especially the inability of many peasants to integrate into urban life due to their lack of education and civilized habits, have long been neglected. In this sense, we cannot be satisfied with the superficially optimistic figures in the chart, but should endeavor to foster the integration of these newcomers by providing them with adequate assistance in educational and cultural aspects, so that they can find easier access to the prosperity and convenience of urban life and be more fully devoted to the development of cities.翻译成英文版两百单词左右的文章
02-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值