首先读入所有的边与询问。将边按颜色分类。
按颜色进行并查集,
若此并查集内的点<= 100,则100*100/2的枚举是否联通。
若此并查集内的点 > 100,则将与这些点相关的所有询问查一遍。
那么时间复杂度为100*100/2*(M/100),或者为M/100*Q。
极限的时候两种方法都在一亿左右了,而且每次还需要在map里搞一搞,还要查询是否联通,不知道为啥没有超时。。
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <cmath> #include <stack> #include <map> #pragma comment(linker, "/STACK:1024000000") #define EPS (1e-8) #define LL long long #define ULL unsigned long long #define _LL __int64 #define INF 0x3f3f3f3f #define Mod 6000007 //** I/O Accelerator Interface .. **/ #define g (c=getchar()) #define d isdigit(g) #define p x=x*10+c-'0' #define n x=x*10+'0'-c #define pp l/=10,p #define nn l/=10,n template<class T> inline T& RD(T &x) { char c; while(!d); x=c-'0'; while(d)p; return x; } template<class T> inline T& RDD(T &x) { char c; while(g,c!='-'&&!isdigit(c)); if (c=='-') { x='0'-g; while(d)n; } else { x=c-'0'; while(d)p; } return x; } inline double& RF(double &x) //scanf("%lf", &x); { char c; while(g,c!='-'&&c!='.'&&!isdigit(c)); if(c=='-')if(g=='.') { x=0; double l=1; while(d)nn; x*=l; } else { x='0'-c; while(d)n; if(c=='.') { double l=1; while(d)nn; x*=l; } } else if(c=='.') { x=0; double l=1; while(d)pp; x*=l; } else { x=c-'0'; while(d)p; if(c=='.') { double l=1; while(d)pp; x*=l; } } return x; } #undef nn #undef pp #undef n #undef p #undef d #undef g using namespace std; struct Qu { int u,v; } query[100010]; struct N { int u,v,c; } edge[100010]; bool cmp(N n1,N n2) { return n1.c < n2.c; } int fa[101000]; bool mark[101000]; map<pair<int,int>,int> M; vector<int> vec[101000],qu; int Find(int x) { int f = x,t; while(f != fa[f]) f = fa[f]; while(x != fa[x]) t = fa[x],fa[x] = f,x = t; return f; } void Merge(int u,int v) { int fu = Find(u); int fv = Find(v); if(fu != fv) { fa[fu] = fv; } } inline void Cal() { int i,j,k,f,v; if(qu.size() > 100) { for(j = qu.size()-1; j >= 0; --j) { f = qu[j]; for(k = vec[f].size()-1; k >= 0; --k) { if(Find(f) == Find(vec[f][k])) M[pair<int,int>(f,vec[f][k])]++; } } } else { for(i = qu.size()-1;i >= 0; --i) { f = qu[i]; for(j = i-1;j >= 0; --j) { v = qu[j]; if(Find(f) == Find(v)) M[pair<int,int>(min(f,v),max(f,v))]++; } } } for(j = qu.size()-1; j >= 0; --j) fa[qu[j]] = qu[j],mark[qu[j]] = false; qu.clear(); } int main() { int i,j,n,m,u,v,f,k,pre; scanf("%d %d",&n,&m); for(i = 1; i <= m; ++i) scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].c); int q; scanf("%d",&q); for(i = 1; i <= q; ++i) { scanf("%d %d",&u,&v); if(u > v) swap(u,v); query[i].u = u; query[i].v = v; if(M.find(pair<int,int>(u,v)) == M.end()) { vec[u].push_back(v); vec[v].push_back(u); M.insert(pair<pair<int,int>,int>(pair<int,int>(u,v),0)); } } sort(edge+1,edge+m+1,cmp); for(i = 1; i <= n; ++i) fa[i] = i; memset(mark,false,sizeof(mark)); map<pair<int,int>,int>::iterator it; for(pre = edge[1].c,i = 1; i <= m; ++i) { if(pre == edge[i].c) { if(mark[edge[i].u] == false) qu.push_back(edge[i].u),mark[edge[i].u] = true; if(mark[edge[i].v] == false) qu.push_back(edge[i].v),mark[edge[i].v] = true; Merge(edge[i].u,edge[i].v); } else { pre = edge[i].c; --i; Cal(); } } Cal(); for(i = 1; i <= q; ++i) { printf("%d\n",M[pair<int,int>(query[i].u,query[i].v)]); } return 0; }
Codeforces 506D Mr. Kitayuta's Colorful Graph 并查集+水水的分类讨论+水水的离线预处理
时间: 2024-10-05 11:28:34