ICode9

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

省选测试9

2021-03-11 08:02:25  阅读:128  来源: 互联网

标签:nxt ch sta 省选 top long int 测试


省选测试 9

T1

​ 咕咕咕咕咕.....

T2

​ 给出一些山顶的坐标\((x_i,y_i)\), 每在一个山顶, 你将会找到当前能够看到的最高的山顶(一个山顶\(P\)能看到另一个山顶\(Q\)当且仅当它们的连线\(P,Q\)只与\(P,Q\)相交).

​ 爬到最高的山顶后你会停下来, 要计算对于每个山顶, 如果从这里开始爬, 会爬过几个山顶.(重复经过算多次). \(y\)坐标相同的情况下选\(x\)比较大的作为最高山顶.

​ \(n <= 5e5, 0 <= x_i, y_i<= 1e6\)

​ 单调栈.

​ 首先我们需要知道在一个山顶可以看到最高的山顶是哪里, 直接单调栈就好了.

​ 设\(to[i]\)为\(i\)这个点为可以看到的最高的点. 我们在往\(to[i]\)走的时候, 可能会经过\(j\)点, \(to[j].y > to[i].y\), 这时候我们需要改变要去的点, 变为\(to[j]\), 也就是说我们需要在\(j\)的答案上再加上一些\(i\)到\(j\)经过的点才能得到\(i\)的答案.

​ 很容易发现这样的关系可以构成一颗树, 我们如果可以找到每个点应该从那些点的答案更新过来, 那么我们就可以建出一颗树, 在树上求出每个点到根的距离就是最终答案了.

​ 设\(pre[i]\)是\(i\)前面第一个\(to[pre[i]].y > to[i].y\)的位置, \(nxt[i]\)是\(i\)后面第一个\(to[nxt[i]].y > to[i].y\)的位置. 如果\(to[i] > i\), 那么我们要走到\(nxt[i]\), 如果\(to[i] < i\), 那么我们要走到\(pre[i]\).

​ 找出每个点的\(pre, nxt\)也用单调栈就可以了.

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 5e5 + 5;
const double eps = 1e-9;
int n, top;
int to[N], pre[N], nxt[N], sta[N];
struct point {
    double x, y;
    point() {}
    point(double X, double Y) { x = X; y = Y; }
} a[N];

point operator - (const point &a, const point &b) { return point(a.x - b.x, a.y - b.y); }

double Cro(point a, point b) { return a.x * b.y - a.y * b.x; }

int dcmp(double x) {
    if(fabs(x) < eps) return 0;
    return x > 0 ? 1 : -1; 
}

void get_to() {
    sta[++ top] = 1; sta[++ top] = 2;
    pre[1] = 1; pre[2] = 1;
    for(int i = 3;i <= n; i++) {
        while(top >= 2 && dcmp(Cro(a[sta[top]] - a[sta[top - 1]], a[i] - a[sta[top - 1]])) > 0) top --;
        sta[++ top] = i; pre[i] = sta[top - 1]; 
    }
    top = 0; sta[++ top] = n; sta[++ top] = n - 1;
    nxt[n] = n; nxt[n - 1] = n;
    for(int i = n - 2;i >= 1; i--) {
        while(top >= 2 && dcmp(Cro(a[sta[top]] - a[sta[top - 1]], a[i] - a[sta[top - 1]])) < 0) top --;
        sta[++ top] = i; nxt[i] = sta[top - 1];
    }
    for(int i = 1;i <= n; i++) {
        // cout << i << " " << pre[i] << " " << nxt[i] << "\n";
        if(a[nxt[i]].y >= a[pre[i]].y) to[i] = nxt[i];
        else to[i] = pre[i];
        // printf("%d : %d\n", i, to[i]);
    }
}

int rt, cnt;
int head[N];
long long ans[N];
struct edge { int to, nxt, val; } e[N << 1];

void add(int x, int y, int z) {
    // cout << x << " " << y << "!!!\n";
    e[++ cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y; e[cnt].val = z;
}

int cmp(int i, int j) {
    if(a[to[i]].y > a[to[j]].y) return 1;
    else if(a[to[i]].y == a[to[j]].y) return a[to[i]].x > a[to[j]].x;
    return 0;
}

void get_pre_nxt() {
    top = 0;
    for(int i = 1;i <= n; i++) {
        while(top && cmp(i, sta[top])) top --;
        // if(i == 9) cout << top << " " << sta[top] << " " << (a[to[sta[top]]].y < a[to[i]].y) << "++++++++++++\n";
        if(top) pre[i] = sta[top];
        else pre[i] = to[i];
        sta[++ top] = i;
    } 
    top = 0;
    for(int i = n;i >= 1; i--) {
        while(top && cmp(i, sta[top])) top --; // ***
        // if(i == 1) cout << top << " " << sta[top] << "\n";
        if(top) nxt[i] = sta[top];
        else nxt[i] = to[i];
        sta[++ top] = i;
    }
    int Max = 0;
    for(int i = 1;i <= n; i++) 
        if(a[i].y >= Max) Max = a[i].y, rt = i;
    for(int i = 1;i <= n; i++) {
        // cout << i << ":" << pre[i] << " " << nxt[i] << "\n";
        if(i == rt) continue ;
        if(to[i] < i) add(max(to[i], pre[i]), i, i - max(to[i], pre[i])); // ***
        if(to[i] > i) add(min(to[i], nxt[i]), i, min(to[i], nxt[i]) - i); // ***
    }
}

void get_ans(int x) {
    for(int i = head[x]; i ; i = e[i].nxt) {
        int y = e[i].to; 
        // cout << x << " " << y << "\n";
        ans[y] = ans[x] + e[i].val; get_ans(y);
    }
}

int main() {

    freopen("mountain.in","r",stdin); freopen("mountain.out","w",stdout);

    n = read(); 
    for(int i = 1;i <= n; i++) a[i].x = read(), a[i].y = read();
    get_to(); get_pre_nxt(); get_ans(rt);
    for(int i = 1;i <= n; i++) printf("%lld\n", ans[i]);

    fclose(stdin); fclose(stdout);

    return 0;
}
/*
4
0 10
1 5
2 0
3 6

10
0 19
1 6
2 9
3 1
4 18
5 16
6 6
7 7
8 18
9 19
*/

T3

​ 小 K 养了 只鸽子,这 只鸽子可以看成平面直角坐标系内的 n 个固定的整点。

​ 同时,为了看住这些鸽子,小 K 可以在 m 个给定的点上选择其中的若干个点安装监视器。

​ 对于一只鸽子,它被监视当且仅当下面三个条件之一成立:

  • 这只鸽子的位置恰好和某个监视器重合。

  • 这只鸽子在其中两个位置不同的监视器连接形成的线段上。

  • 这只鸽子在三个不共线的监视器所构成的三角形.

​ 现在小 K 要让所有鸽子都被监视,请问他最少需要选择多少个给定的位置设置监视器。

\(2 <= n <= 1e5,3 <= m <= 500\).

​ 凸包.

​ 对于两个监视器\(A,B\), 我们可以连一条从\(A\)到\(B\)的边(注意有方向)当且仅当所有鸽子都在它的左边, 这个用叉积判断就可以了.

​ 所有监视器都连完边后, 我们用Floyd求最小环就可以得到答案了.

​ 怎么判断所有鸽子都在一条线的左边呢? 我们可以把鸽子的凸包求出来, 只需要判断离这条直线最近的点是否在直线的左边就好了.我们可以在凸包上二分斜率来得到这个点.

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 1e5 + 5, inf = 1e9;
const double eps = 1e-9;
int n, m, topx, tops;
struct point { 
    double x, y; 
    point() {}
    point(double X, double Y) { x = X; y = Y; }
    friend int operator < (const point &a, const point &b) {
        return a.x == b.x ? a.y < b.y : a.x < b.x;
    }
} a[N], b[N], stax[N], stas[N];

point operator - (const point &a, const point &b) { return point(a.x - b.x, a.y - b.y); }

double Cro(point a, point b) { return a.x * b.y - a.y * b.x; }

int dcmp(double x) {
    if(fabs(x) < eps) return 0;
    return x > 0 ? 1 : -1;
}

void ConvexHall() {
    sort(a + 1, a + n + 1);
    stax[++ topx] = a[1]; stax[++ topx] = a[2];
    for(int i = 3;i <= n; i++) {
        while(topx >= 2 && dcmp(Cro(stax[topx] - stax[topx - 1], a[i] - stax[topx - 1])) <= 0) topx --;
        stax[++ topx] = a[i];
    }
    stas[++ tops] = a[n]; stas[++ tops] = a[n - 1];
    for(int i = n - 2;i >= 1; i--) {
        while(tops >= 2 && dcmp(Cro(stas[tops] - stas[tops - 1], a[i] - stas[tops - 1])) <= 0) tops --;
        stas[++ tops] = a[i];
    }
}

double xl(point a, point b) {
    return (a.y - b.y) / (a.x - b.x);
}

int judge(int i, int j) {
    double k = xl(b[i], b[j]);
    // cout << i << " " << j << " " << k << "\n";
    int l = 2, r = tops - 1, mid;
    point ans1 = a[1], ans2 = a[n];
    while(l <= r) {
        mid = (l + r) >> 1;
        // cout << l << " " << r << "\n";
        double z1 = xl(stas[mid - 1], stas[mid]), z2 = xl(stas[mid], stas[mid + 1]);
        int t1 = dcmp(k - z1), t2 = dcmp(k - z2);
        if((t1 == 0 && t2 == 0) || (t1 != t2)) { ans1 = stas[mid]; break; } 
        else if(t1 > 0 && t2 > 0) r = mid - 1;
        else l = mid + 1;
    }
    l = 2, r = topx - 1;
    while(l <= r) {
        mid = (l + r) >> 1;
        // cout << l << " " << r << "\n";
        double z1 = xl(stax[mid - 1], stax[mid]), z2 = xl(stax[mid], stax[mid + 1]);
        int t1 = dcmp(k - z1), t2 = dcmp(k - z2);
        if((t1 == 0 && t2 == 0) || (t1 != t2)) { ans2 = stax[mid]; break; } 
        else if(t1 < 0 && t2 < 0) r = mid - 1;
        else l = mid + 1;
    }
    if(dcmp(Cro(ans1 - b[i], b[j] - b[i])) >= 0) {
        if(dcmp(Cro(a[1] - b[i], b[j] - b[i])) >= 0 && dcmp(Cro(a[n] - b[i], b[j] - b[i])) >= 0) return 1;
    }
    else if(dcmp(Cro(ans2 - b[i], b[j] - b[i])) <= 0) {
        if(dcmp(Cro(a[1] - b[i], b[j] - b[i])) <= 0 && dcmp(Cro(a[n] - b[i], b[j] - b[i])) <= 0) return 1;
    }
    else return 0;
}

long long ans;
long long f[505][505], d[505][505];

int main() {

    freopen("lo.in","r",stdin); freopen("lo.out","w",stdout);

    n = read(); m = read();
    for(int i = 1;i <= n; i++) a[i].x = read(), a[i].y = read(); 
    for(int i = 1;i <= m; i++) b[i].x = read(), b[i].y = read();
    ConvexHall();
    // for(int i = 1;i <= tops; i++) cout << stas[i].x << " " << stas[i].y << "!!!\n";
    // for(int i = 1;i <= topx; i++) cout << stax[i].x << " " << stax[i].y << "|||\n"; 

    ans = inf;
    for(int i = 1;i <= m; i++)
        for(int j = 1;j <= m; j++) f[i][j] = d[i][j] = inf;
    sort(b + 1, b + m + 1);
    for(int i = 1;i <= m; i++)
        for(int j = i + 1;j <= m; j++) 
            if(judge(i, j)) f[i][j] = f[j][i] = d[i][j] = d[j][i] = 1;
    
    for(int k = 1;k <= m; k++) {
        for(int i = 1;i <= m; i++) {
            for(int j = 1;j <= m; j++) {
                ans = min(ans, d[i][k] + d[k][j] + f[i][j]);
            }
        }
        for(int i = 1;i <= m; i++) {
            for(int j = 1;j <= m; j++) {
                ans = min(ans, f[i][k] + f[k][j] + f[i][j]);
                // cout << f[i][k] << " " << f[k][j] << " " << f[i][j] << "\n";
                if(f[i][k] + f[k][j] < f[i][j]) f[i][j] = f[i][k] + f[k][j];
            }
        }
    }
    printf("%lld", ans > m ? -1 : ans);


    fclose(stdin); fclose(stdout);

    return 0;
}

/*
4 4
0 0
1 0
0 1
-1 0
0 1
1 0
0 -1
-1 0

2 4
-1 0
1 0
-2 -1
-2 1
2 -1
2 1
*/

标签:nxt,ch,sta,省选,top,long,int,测试
来源: https://www.cnblogs.com/czhui666/p/14515454.html

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

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

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

ICode9版权所有