BZOJ5206 [Jsoi2017]原力[根号分治]

这是一个三元环计数的裸题,只是多了一个颜色的区分和权值的计算罢了。

有一种根号分治的做法(by gxz)

这种复杂度的证明特别显然,思路非常简单,不过带一个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 }
View Code

总结:这相当于是把原来$O(mn)$的做法尝试通过连边、度数等减少枚举。。

posted @ 2019-11-09 20:23  Ametsuji_akiya  阅读(222)  评论(0编辑  收藏  举报