BZOJ5206: [Jsoi2017]原力
阿新 • • 發佈:2019-01-06
math geo clas mat ble head 直接 只需要 efi
BZOJ5206: [Jsoi2017]原力
https://lydsy.com/JudgeOnline/problem.php?id=5206
分析:
- 比較厲害的三元環問題。
- 設立閾值,當點的度數大於根號時,考慮直接枚舉三個點算答案。
- 否則,只需要考慮存在一個點度數小於等於根號的情況,枚舉這個點,枚舉它的兩個出邊即可,需要保證它是所選三個點中度數小於根號的編號最小的一個。
- 如果距離用\(map\)存,時間復雜度會多一個\(\log\)
代碼:
#include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> #include <map> #include <cmath> using namespace std; #define N 50050 #define M 200050 #define mod 1000000007 typedef long long ll; int n,m,head[N],to[M],nxt[M],val[M],opp[M],cnt,du[N],a[N],la,vis[N]; char opt[5]; map<int,ll>dis[N][3]; inline void add(int u,int v,int w,int o) { to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w; opp[cnt]=o; } int main() { scanf("%d%d",&n,&m); int i,x,y,z,o,S=sqrt(n); for(i=1;i<=m;i++) { scanf("%d%d%d%s",&x,&y,&z,opt); if(opt[0]=='R') o=0; else if(opt[0]=='G') o=1; else o=2; dis[x][o][y]+=z; dis[y][o][x]+=z; add(x,y,z,o); add(y,x,z,o); du[x]++; du[y]++; } ll ans=0; for(i=1;i<=n;i++) { if(du[i]>S) a[++la]=i; } int j,k; for(i=1;i<=la;i++) { x=a[i]; for(j=1;j<=la;j++) if(dis[x][0][a[j]]) { y=a[j]; ll t1=dis[x][0][y]; for(k=1;k<=la;k++) if(dis[y][1][a[k]]) { z=a[k]; ans=(ans+t1*dis[y][1][z]%mod*dis[z][2][x])%mod; } } } for(x=1;x<=n;x++) if(du[x]<=S) { vis[x]=1; for(i=head[x];i;i=nxt[i]) if(!vis[to[i]]) { ll t=val[i]; for(j=nxt[i];j;j=nxt[j]) if(!vis[to[j]]&&opp[i]!=opp[j]&&to[i]!=to[j]) { ans=(ans+t*val[j]%mod*dis[to[i]][3-opp[i]-opp[j]][to[j]])%mod; } } } printf("%lld\n",ans); }
BZOJ5206: [Jsoi2017]原力