Gym 100796E Permutation Polygon [树状数组]

本文探讨了在正N边形中,根据特定排列建立城市间高速公路的数学模型,通过分析高速公路之间的交点数量,解决城市间的连接问题。利用排序和树状数组等数据结构进行高效计算,旨在最小化复杂度并提供解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

  • There are n cities in Regularia, Alice's homeland. They are located at the vertices of a regular n-gon. The cities are numbered from 1 ton in a clockwise order (see the figure).

    The people of Regularia love Alice so much that they made her the queen of the country. Alice wants to prove herself, so she has ordered a construction of a new highway system connecting cities of Regularia. Alice has come up with a plan to build the highways, which is ann-permutation p1, p2, ..., pn. Specifically, for a city numbered i, Alice wants to build a highway between the cities i and pi, where piis the number of some other city. A highway is a straight line connecting two cities. According to Alice's plan, any two cities will be connected by no more than a single highway.

    Of course, some of the highways may intersect one another. Two highways are said to intersect if and only if there is a unique point that belongs to both of the highways and is not a city. This point is called a junction of the two highways. Even if more than two highways meet at a single point, each pair has its own separate junction. As a complicated and expensive interchange has to be built at each junction, Alice is interested in the total number of junctions in her plan. Help her find this number!

    For example, the plan for a permutation 4, 1, 5, 3, 2 is shown in the figure.

Input

The first line contains a single integer n, the number of cities in Regularia (3 ≤ n ≤ 105). The next line contains n space-separated integers p1, p2, ..., pn, which is a permutation of length n. It is guaranteed that i ≠ pi for any i and that no two cities will be connected by more than a single highway.

Output

Output a single integer — the total number of junctions in Alice's plan.

大致题意:

一个正N边形,每个顶点的标号为1..N,现在给出一些<X,Y>表示两点有一条连线,问在多边形内部有多少个交点。(多个点在同一位置算多个)

解法:

可以发现如果两条线有交点,那么其两端的 index (x,y)(保证X<Y),肯定是交错的,即如同 x'  X  y'  Y ,那么可以考虑对X排序,保证x'比当前枚举的X小,然后查看X到Y之间(不包括两端),有多少个 y’ 即可,这个过程可以用树状数组实现。

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
#include<stdlib.h>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<bitset>
#pragma comment(linker, "/STACK:1024000000,1024000000")
template <class T>
bool scanff(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}
#define inf 1073741823
#define llinf 4611686018427387903LL
#define PI acos(-1.0)
#define lth (th<<1)
#define rth (th<<1|1)
#define rep(i,a,b) for(int i=int(a);i<=int(b);i++)
#define drep(i,a,b) for(int i=int(a);i>=int(b);i--)
#define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next)
#define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++)
#define mem(x,val) memset(x,val,sizeof(x))
#define mkp(a,b) make_pair(a,b)
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;



struct node{
    int x,y;
    bool operator < (const node temp)const{
        if(x==temp.x)return y<temp.y;
        return x<temp.x;
    }
}a[100100];
int n;
int c[100100];
#define lowbit(x) (x&(-x))
void add(int x){
    for(int i=x;i<=n;i+=lowbit(i))c[i]++;
}
int getsum(int l,int r){
    int s1=0,s2=0;
    for(int i=l-1;i>0;i-=lowbit(i))s1+=c[i];
    for(int i=r;i>0;i-=lowbit(i))s2+=c[i];
    return s2-s1;
}
int lor[100100][2];
int main(){
    scanff(n);
    rep(i,1,n){
        int x=i;
        int y;
        scanff(y);
        if(x>y)swap(x,y);
        a[i].x=x;
        a[i].y=y;
    }
    ll ans=0;
    sort(a+1,a+1+n);
    rep(i,1,n){
        if(i==1||a[i].x!=a[i-1].x)lor[a[i].x][0]=i;
        if(i==n||a[i].x!=a[i+1].x)lor[a[i].x][1]=i;
    }
    rep(i,1,n){
        if(lor[i][0]==0)continue;
        rep(j,lor[i][0],lor[i][1]){
            ans+=ll(getsum(a[j].x+1,a[j].y-1));
        }
        rep(j,lor[i][0],lor[i][1]){
            add(a[j].y);
        }
    }
    printf("%lld\n",ans);
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值