brute force ? 其实是平方分解。很容易想到的是每一个颜色建一个图,然后并查集维护一下连通性。

问题在于颜色有O(m)种,每种颜色的图点数都是O(n)的,因此并查集的空间只能重复利用。

但是可以把以O(m)的空间把有用的连通块信息保留下来。

之后的处理可以借鉴分块的思想。

记点v属于的连通块数量为b(v),对于询问x,y ,根据点所在的连通块信息,可以以O(max(b(x),b(y)))的时间回答出来。

设置一个阀值B,对于b(v)>B,提前预处理,小于B的就暴力回答。

因为一条边最多增加两个b(v)值,所有b(v)的和是O(m)的。 最多有m/B个v满足b(v)大于B,对于每个这样的v,O(m)历遍,O(m)的空间记录答案。

两部分的复杂度是O(m/B*m + B*q),类似分块的取法,取B = m/sqrt(q),复杂度为O(m*sqrt(q))。

/*********************************************************
* --------------Alfheim-------------- *
* author AbyssalFish *
**********************************************************/
#include<bits/stdc++.h>
using namespace std; typedef long long ll; const int maxn = 1e5+, maxm = 1e5+; int pa[maxn], rak[maxn]; int fd(int x)
{
return pa[x]? pa[x] = fd(pa[x]): x;
} inline void joint(int a,int b)
{
int x = fd(a), y = fd(b);
if(x != y){
if(rak[x] < rak[y]){
pa[x] = y;
}
else {
pa[y] = x;
if(rak[x] == rak[y]) rak[x]++;
}
}
} int a[maxm],b[maxm];
bool vis[maxn]; int hd_c[maxn], nx_e[maxm]; inline void add_e(int cl,int i)
{
nx_e[i] = hd_c[cl];
hd_c[cl] = i;
} typedef vector<int> Block;
typedef vector<int> v_int; vector<Block> blc;
Block tmp[maxn];
v_int in_blk[maxn]; inline void add_blc(int x)
{
if(!vis[x]){
vis[x] = true;
tmp[fd(x)].push_back(x);
}
} inline void dump(int x)
{
if(tmp[x].size() > ){
blc.push_back(tmp[x]);
tmp[x].clear();
}
if(vis[x]){
vis[x] = false;
rak[x] = pa[x] = ;
}
} const uint32_t MAXB = ; int ans[MAXB+][maxn];
int id[maxn]; //#define LOCAL
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif
//cout<<(2*maxm/sqrt(2*maxm));
int n,m,q;
scanf("%d%d",&n,&m);
uint32_t B = floor(*m/sqrt(*m));
int i,j;
for(i = ; i <= m; i++){
scanf("%d%d%d",a+i,b+i,&j);
add_e(j,i);
} for(i = ; i <= m; i++){
for(j = hd_c[i]; j; j = nx_e[j]){
joint(a[j],b[j]);
}
for(j = hd_c[i]; j; j = nx_e[j]){
add_blc(a[j]);
add_blc(b[j]);
}
for(j = hd_c[i]; j; j = nx_e[j]){
dump(a[j]);
dump(b[j]);
}
} for(i = ; i < (int)blc.size(); i++){
for(auto v: blc[i]){
in_blk[v].push_back(i);
}
} int id_cnt = ;
for(i = ; i <= n; i++){
if(in_blk[i].size() > B){
id[i] = ++id_cnt;
for(auto b_id: in_blk[i]){
for(auto v: blc[b_id]){
ans[id_cnt][v]++;
}
}
}
} scanf("%d",&q);
while(q--){
int x,y; scanf("%d%d",&x,&y);
int res;
if(id[x]) res = ans[id[x]][y];
else if(id[y]) res = ans[id[y]][x];
else {
res = i = j = ;
v_int &X = in_blk[x], &Y = in_blk[y];
n = X.size(); m = Y.size();
while(i < n && j < m){
if(X[i] == Y[j]){
res++; i++; j++;
}
else {
X[i] < Y[j] ? i++ : j++;
}
}
}
printf("%d\n",res);
} return ;
}

最新文章

  1. 【Linux】crontab 定时任务
  2. 什么是Servlet?
  3. Java面试题整理
  4. Lisp使用Lambda语法
  5. python unittest基本介绍
  6. Cocoa Foundation框架学习笔记 - NSCalendar
  7. Dapper中使用存储分页。
  8. hdu - 4709 - Herding
  9. Appium实现的技巧
  10. 点击grid单元格弹出新窗口
  11. Sublime Text3—自带快捷键介绍
  12. java语言基础--方法的执行图解
  13. CSS制作镂空字体
  14. An Introduction To The SQLite C/C++ Interface
  15. bat 复制文件夹,文件名递增 等操作
  16. nw.js---创建一个hello word的方法
  17. YOLO(5) YOLO2 代码讲解
  18. sqlserver 查看当前连接数
  19. javascript基础拾遗(三)
  20. Linux下几种反弹Shell方法的总结与理解

热门文章

  1. tp 查询
  2. java——cmd命令编译带包名的源程序
  3. java list分页
  4. 数据结构---Java---ArrayList
  5. 01-消息中间件概述和ActiveMq入门
  6. linux 测试远程主机端口
  7. js 基础学习笔记(一)
  8. POJ 3694——Network——————【连通图,LCA求桥】
  9. php7.0.24-nts配置步骤
  10. Java Executors小结