基站建设

基站建设_第1张图片

可以发现所有合法的建站方案,都是两个有且只有一条公共边的三元环拼在一起。题目转化为枚举三元环。
这里给出一种 O(mm) O ( m m ) 的方法。
将所有点分成两类:度大于等于 m m 的点称为大点,小于 m m 的点称为小点。
1.枚举三个大点能否组成三元环。
2.枚举小点,以及和它相邻的两个点,能否组成三元环。
判断两点之间有无连边需要使用哈希。

复杂度证明:
1.大点数目不超过 m m ,枚举复杂度 O(m3) O ( m 3 )
2.设小点有b条边和它相连。枚举复杂度约为 O(mbb2) O ( m b b 2 )
另外可以证明 m m 是大点小点的最优临界。
上述两步的复杂度都是 O(mm) O ( m m )

也算一道模板题了。个人比较懒,哈希不写判重,冲突就去买彩票

#include
#include
#include
#define Pair pair
#define mp(x,y) make_pair(x,y)
#define rint register int
using namespace std;
typedef long long LL;
const int P=1e7+7;
struct node {
    int u,v,ID;
} edge[200005];
int head[50005],vet[400005],nxt[400005],idn[400005],num;
int ha[(int)(1e7+10)];
int bp[50005];
int val[50005],deg[50005],bs;
Pair mx[200005][2];
int n,m;
inline void addedge(int &x,int &y,int &i) {
    num++;vet[num]=y;idn[num]=i;nxt[num]=head[x];head[x]=num;
    num++;vet[num]=x;idn[num]=i;nxt[num]=head[y];head[y]=num;
}
inline int gethash(int &x,int &y) {
    return ((LL)x*(n+1)+y)%P;
}
inline void update(int &v,int &i) {
    if (val[v]>mx[i][0].first && v!=mx[i][0].second) {
        mx[i][1]=mx[i][0];
        mx[i][0]=mp(val[v],v);
    }
    else if (val[v]>mx[i][1].first && v!=mx[i][0].second) mx[i][1]=mp(val[v],v);
}
int main() {
    scanf("%d%d",&n,&m);bs=(int)sqrt((double)m);
    for (rint i=1;i<=n;i++) scanf("%d",&val[i]);
    for (rint i=1;i<=m;i++) {
        int x,y;
        scanf("%d%d",&x,&y);edge[i]=(node){x,y,i};
        addedge(x,y,i);deg[x]++;deg[y]++;
        ha[gethash(x,y)]=ha[gethash(y,x)]=i;
    }
    for (rint i=1;i<=n;i++) if (deg[i]>=bs) bp[++bp[0]]=i;
    for (rint i=3;i<=bp[0];i++) {
        for (rint j=2;jif (ha[gethash(bp[i],bp[j])]==0) continue;
            for (rint k=1;kif (y==0 || z==0) continue;
                update(bp[i],z);update(bp[j],y);update(bp[k],x);
            }
        }
    }
    for (rint i=1;i<=n;i++) {
        if (deg[i]>=bs) continue;
        for (rint e1=head[i];e1;e1=nxt[e1]) {
            for (rint e2=head[i];e2!=e1;e2=nxt[e2]) {
                rint j=vet[e1],k=vet[e2],x=ha[gethash(j,k)];
                if (x==0) continue;
                update(i,x);update(j,idn[e2]);update(k,idn[e1]);
            }
        }
    }
    int ans=0;
    for (rint i=1;i<=m;i++) {
        if (mx[i][1].second==0) continue;
        ans=max(ans,(val[edge[i].u]+1)*(val[edge[i].v]+1)+mx[i][0].first*mx[i][1].first);
    }
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(基站建设)