BZOJ5206 [Jsoi2017]原力[根号分治]
这是一个三元环计数的裸题,只是多了一个颜色的区分和权值的计算罢了。
这种复杂度的证明特别显然,思路非常简单,不过带一个log,可以用unordered_map或者bitset之类的$O(1)$判连通。
我的做法的话采用了一个比较奇怪的思路?每条边,度数大的点向度数小的点连有向边,然后枚举第一层点,枚举出发到达的第二层点,这两层加起来复杂度总的是$O(m)$,然后从第二层点枚举出边到第三层点,看第三层点和第一层点是不是连通的,这个复杂度我好像在这里写过证明,就不贴了。注意一下重边的话,只要把相同颜色的权值累加起来做乘法就行(line47)。
理论上说是根号的做法,但是我跑了9s???
人家带一个log的都比我跑的快一倍,莫非我复杂度是假的?
不清楚,如果有神仙指导不胜感激。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 #define mst(x) memset(x,0,sizeof x) 8 #define dbg(x) cerr << #x << " = " << x <<endl 9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl 10 using namespace std; 11 typedef long long ll; 12 typedef double db; 13 typedef pair<int,int> pii; 14 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 15 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;} 17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;} 18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;} 19 template<typename T>inline T read(T&x){ 20 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;else if(c=='R'||c=='G'||c=='B'){x=c;break;} 21 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x; 22 } 23 const int N=1e5+7,P=1e9+7; 24 struct thxorz{ 25 int head[N],w[N<<1],nxt[N<<1],to[N<<1],typ[N<<1],tot; 26 thxorz(){tot=1;} 27 inline void add(int x,int y,int z,int ty){to[++tot]=y,nxt[tot]=head[x],head[x]=tot,w[tot]=z,typ[tot]=ty;} 28 }G,E; 29 inline void add(int&a,int b){a+=b;a>=P&&(a-=P);} 30 inline int mod(int a){return a>=P?a-=P:a;} 31 int deg[N],vis[N][3],val[N][3]; 32 int n,m,ans; 33 inline int cmp(int a,int b){return deg[a]==deg[b]?a<b:deg[a]<deg[b];} 34 35 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout); 36 read(n),read(m); 37 for(register int i=1;i<=m<<1;i+=2)++deg[read(E.to[i])],++deg[read(E.to[i+1])],read(E.w[i]),read(E.typ[i]); 38 for(register int i=1;i<=m<<1;i+=2){ 39 if(!cmp(E.to[i],E.to[i+1]))G.add(E.to[i+1],E.to[i],E.w[i],E.typ[i]=='R'?0:(E.typ[i]=='G'?1:2)); 40 else G.add(E.to[i],E.to[i+1],E.w[i],E.typ[i]=='R'?0:(E.typ[i]=='G'?1:2)); 41 } 42 for(register int x=1;x<=n;++x){//x 43 #define y G.to[j] 44 #define t G.typ[j] 45 for(register int j=G.head[x];j;j=G.nxt[j]){ 46 if(vis[y][t]^x)vis[y][t]=x,val[y][t]=G.w[j]; 47 else add(val[y][t],G.w[j]); 48 } 49 #define z G.to[k] 50 #define tt G.typ[k] 51 for(register int j=G.head[x];j;j=G.nxt[j]){//y 52 for(register int k=G.head[y];k;k=G.nxt[k])if(t^tt){//z 53 if(vis[z][3-t-tt]==x)add(ans,G.w[j]*1ll*G.w[k]%P*val[z][3-t-tt]%P); 54 } 55 } 56 } 57 printf("%d\n",ans); 58 return 0; 59 }
总结:这相当于是把原来$O(mn)$的做法尝试通过连边、度数等减少枚举。。