[JSOI2017]原力
题目大意:
一个$n(n\le5\times10^4)$个点,$m(m\le10^5)$条边的无向图。每条边有一个边权$w_i(w_i\le10^6)$和一个附加属性$t_i(t_i\in\{R,G,B\})$。定义一个三元环的价值为个条边权值之积,求所有满足每条边附加属性互不相同的三元环的价值和。
思路:
对结点按照度数分为两组分块,度数$\ge\sqrt m$的算作重点,否则算轻点。对于三元环三个顶点都是重点的情况,直接暴力即可,复杂度$O(m\sqrt m)$。对于含有轻点的三元环,$O(m)$枚举第一个点及一条出边,$O(\sqrt m)$枚举第二条出边,复杂度还是$O(m\sqrt m)$。这里对于边权的查询应该是利用哈希实现的,但是用map也能过,复杂度$O(m\sqrt m\log m)$。
1 #include<map> 2 #include<cmath> 3 #include<cstdio> 4 #include<cctype> 5 #include<cstring> 6 typedef long long int64; 7 inline int getint() { 8 register char ch; 9 while(!isdigit(ch=getchar())); 10 register int x=ch^'0'; 11 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 12 return x; 13 } 14 inline int gettype() { 15 register char ch; 16 while(!isalpha(ch=getchar())); 17 return ch!='R'?ch!='G'?0:1:2; 18 } 19 const int N=5e4+1,M=2e5,mod=1e9+7; 20 struct Edge { 21 int to,w,type,next; 22 }; 23 Edge e[M]; 24 int h[N],sz,deg[N],c[N]; 25 struct Node { 26 int u,v,type; 27 bool operator < (const Node &another) const { 28 if(u!=another.u) return u<another.u; 29 if(v!=another.v) return v<another.v; 30 return type<another.type; 31 } 32 }; 33 std::map<Node,int> map; 34 inline void add_edge(const int &u,const int &v,const int &w,const int &t) { 35 e[sz]=(Edge){v,w,t,h[u]};h[u]=sz++;deg[u]++; 36 (map[(Node){u,v,t}]+=w)%=mod; 37 } 38 int main() { 39 memset(h,-1,sizeof h); 40 const int n=getint(),m=getint(),block=sqrt(m); 41 for(register int i=0;i<m;i++) { 42 const int u=getint(),v=getint(),w=getint(),t=gettype(); 43 add_edge(u,v,w,t); 44 add_edge(v,u,w,t); 45 } 46 for(register int i=1;i<=n;i++) { 47 if(deg[i]>=block) c[++c[0]]=i; 48 } 49 int ans=0; 50 for(register int i=1;i<=c[0];i++) { 51 for(register int j=1;j<=c[0];j++) { 52 for(register int k=1;k<=c[0];k++) { 53 (ans+=(int64)map[(Node){c[i],c[j],0}]*map[(Node){c[j],c[k],1}]%mod*map[(Node){c[k],c[i],2}]%mod)%=mod; 54 } 55 } 56 } 57 for(register int i=1;i<=n;i++) { 58 if(deg[i]>=block) continue; 59 for(register int j=h[i];~j;j=e[j].next) { 60 if(deg[e[j].to]<block&&e[j].to<=i) continue; 61 for(register int k=e[j].next;~k;k=e[k].next) { 62 if(e[j].type==e[k].type||(deg[e[k].to]<block&&e[k].to<=i)) continue; 63 (ans+=(int64)map[(Node){e[j].to,e[k].to,3-e[j].type-e[k].type}]*e[j].w%mod*e[k].w%mod)%=mod; 64 } 65 } 66 } 67 printf("%d\n",ans); 68 return 0; 69 }