BZOJ 3498: PA2009 Cakes
Description
\(n\)个点\(m\)条边,求所有三元环,一个三元环的贡献为三个点中权值最大的点.\(n\leqslant 1\times 10^5,n\leqslant 2.5\times 10^5\)
Solution
分类讨论.
只从权值大的点连向权值小的点,因为可能权值相同,顺序需要确定下来.
枚举所有边.
如果一个点的度数小于等于\(\sqrt m\)那么枚举所有的点,看看他和另一个点有没有连边,直接用map存一下...
如果度数大于\(\sqrt m\)那么枚举另一个点的所有相邻的点,如果另一个点度数大于\(\sqrt m\),那么这种情况最多有\(\sqrt m\)个...
总复杂度\(O(m\sqrt m)\)
Code
/************************************************************** Problem: 3498 User: BeiYu Language: C++ Result: Accepted Time:5376 ms Memory:18248 kb ****************************************************************/ #include <bits/stdc++.h> using namespace std; #define uor(i,j,k) for(int i=j;i<=(int)k;i++) #define uep(i,j,k) for(int i=j;i<(int)k;i++) typedef long long ll; const int N = 100050; inline int in(int x=0,char s=getchar()) { while(s>'9'||s<'0')s=getchar(); while(s>='0'&&s<='9')x=x*10+s-'0',s=getchar();return x; } int n,m,B;ll ans=0; int a[N],de[N],du[N],id[N],rk[N]; vector<int> g[N]; map<int,bool> mp[N]; int cmp(const int &x,const int &y) { return a[x]<a[y]; } void AddEdge(int fr,int to) { g[fr].push_back(to),du[fr]++; } int main() { n=in(),m=in(),B=sqrt(m)+1; uor(i,1,n) a[i]=in(),id[i]=i; sort(id+1,id+n+1,cmp); uor(i,1,n) rk[id[i]]=i; uor(i,1,m) { int u=in(),v=in(); if(rk[u]<rk[v]) swap(u,v); AddEdge(u,v); } uor(i,1,n) { int u=id[i]; uep(j,0,g[u].size()) de[g[u][j]]=i; uep(j,0,g[u].size()) { int v=g[u][j]; if(du[v]>B) uep(k,0,g[u].size()) ans+=mp[v][g[u][k]]?a[u]:0; else uep(k,0,g[v].size()) ans+=de[g[v][k]]==i?a[u]:0; mp[u][v]=1; } }return printf("%lld\n",ans),0; }