1. 程式人生 > >BZOJ 3498 PA2009 Cakes

BZOJ 3498 PA2009 Cakes

否則 一個 char arr nod 大致 fine const bool

本題BZOJ權限題,但在bzojch上可以看題面。

題意:

  N個點m條無向邊,每個點有一個點權a。

  對於任意一個三元環(i,j,k)(i<j<k),它的貢獻為max(ai,aj,ak)

  求所有三元環的貢獻和。

  N<100000,m<250000

Solution:

  本題裸的三元環計數。

  無向圖三元環計數的問題大致做法:

    統計每個點的度數,對於一條無向邊$<u,v>$,若$deg[u]==deg[v]$則從編號小的點向編號大的點連有向邊,否則從$deg$較大的向較小的點連有向邊。

    這樣無向圖就變為了一個DAG模型,然後掃一下每個點$u$,對其出點$v$打標記$vis[v]=u$,再對每個出點$v$的出點$w$判斷是否滿足$vis[w]=u$即可。

  分析一波時間復雜度:

    不難發現對於每條邊$u\rightarrow v$,我們需要統計的是出度個數$out_v$,那麽總的貢獻是$\sum_\limits{i=1}^{i\leq n}{out_i}$。

    假設$out_v\leq \sqrt m$,由於$u\rightarrow v$,則$deg_u\geq deg_v$,這樣$u$最多$n$個,於是此時最壞復雜度為$O(n\sqrt m)$;

    假設$out_v>\sqrt m$,由於$u\rightarrow v$,則$deg_u\geq deg_v$,於是$deg_u>\sqrt m$,這樣$u$最多$\sqrt m$個,於是此時最壞時間復雜度$O(m\sqrt m)$。

  綜上所述,$n,m$同階時,該算法時間復雜度$O(n\sqrt m)$。

  那麽本題三元環計數時累加答案就好了。

代碼:

/*Code by 520 -- 9.10*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
using
namespace std; const int N=500005; int n,m,a[N],deg[N],vis[N]; int to[N],net[N],h[N],cnt; struct node{ int u,v; }e[N]; ll ans; int gi(){ int a=0;char x=getchar();bool f=0; while((x<0||x>9)&&x!=-)x=getchar(); if(x==-)x=getchar(),f=1; while(x>=0&&x<=9)a=(a<<3)+(a<<1)+(x^48),x=getchar(); return f?-a:a; } il void add(int u,int v){to[++cnt]=v,net[cnt]=h[u],h[u]=cnt;} int main(){ n=gi(),m=gi(); For(i,1,n) a[i]=gi(); For(i,1,m) e[i].u=gi(),e[i].v=gi(),++deg[e[i].u],++deg[e[i].v]; For(i,1,m) { RE int u=e[i].u,v=e[i].v; if(deg[u]<deg[v]||deg[u]==deg[v]&&u>v) swap(u,v); add(u,v); } For(u,1,n){ for(RE int i=h[u];i;i=net[i]) vis[to[i]]=u; for(RE int i=h[u];i;i=net[i]) { RE int v=to[i]; for(RE int j=h[v];j;j=net[j]){ RE int w=to[j]; if(vis[w]==u)ans+=max(a[u],max(a[v],a[w])); } } } cout<<ans; return 0; }

BZOJ 3498 PA2009 Cakes