题目大意:

给定一张n个点m条边的无向图,每条边有两种权.每次询问某两个点之间是否存在一条路径上的边的两种权的最大值分别等于给定值.

n,q <= 50000. m <= 100000

题解:

通过分析可以得到,我们能经过的所有的边的两种权一定均分别不大于给定的值.

把这些边称作可行边。那么我们把所有的可行边加入到图当中,然后判断询问的两个点是不是联通.

如果联通我们再进一步判断一下所有与其所在的联通块联通的所有边的两种边权的分别的最大值.

然后就是考虑如何快速统计出所有的边并将其加入到联通块中.

我们选择如下策略: 把所有的边按第一种权排序,然后分块.

每块内按照第二种权排序

事实证明上面划掉的方法直接TLE

我们考虑离线所有的操作,然后每次对第一种权在某一个块内的所有询问.

我们知道如果某个询问的第一种权在块i中,那么1 ~ i-`中的所有边的第一种权都符合条件.

所以这时候对1 ~ i-1块中的所有边按照第二种权排序.

如果我们处理询问的时候按照第二种权递增访问就可以做到线性统计了.

所以我们将所有此时应该处理的询问按照第二种权排序.

那么我们可以线性统计所有在1 ~ i-1块中的边完成所有此时的询问.

那么在第i个块中的呢 ?

直接暴力查询,然后维护可持久化并查集即可.

我们直接记录所有的操作,然后暴力撤销即可.

不要问我复杂度是多少,O(跑的过)

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define rg register int
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 100010;
const int maxm = 100010;
struct Edge{
int id;
int u,v,a,b;
}e[maxm],q[maxm],tmp[maxm];
int cnt;
inline bool cmpa(const Edge &a,const Edge &b){
return a.a == b.a ? a.b < b.b : a.a < b.a;
}
inline bool cmpb(const Edge &a,const Edge &b){
return a.b == b.b ? a.a < b.a : a.b < b.b;
}
int n,m;
struct Node{
int idx,idy,fa,siz,mxa,mxb;
Node(){}
Node(const int &a,const int &b,const int &c
,const int &d,const int &e,const int &f){
idx = a;idy = b;fa = c;siz = d;mxa = e;mxb = f;
}
}sta[maxm];
int top;
int fa[maxn],siz[maxn],mxa[maxn],mxb[maxn];
inline void clear(){
for(int i=1;i<=n;++i){
fa[i] = i;siz[i] = 1;
mxa[i] = mxb[i] = -1;
}
}
inline int find(int x){
while(x != fa[x]) x = fa[x];
return x;
}
inline void Union(const Edge &e){
int x = find(e.u),y = find(e.v);
if(siz[x] > siz[y]) swap(x,y);
sta[++top] = Node(x,y,fa[x],siz[y],mxa[y],mxb[y]);
mxa[y] = max(mxa[y],max(mxa[x],e.a));
mxb[y] = max(mxb[y],max(mxb[x],e.b));
if(x == y) return ;
siz[y] += siz[x];fa[x] = y;
}
inline void Undo(){
while(top){
fa[sta[top].idx] = sta[top].fa;
siz[sta[top].idy] = sta[top].siz;
mxa[sta[top].idy] = sta[top].mxa;
mxb[sta[top].idy] = sta[top].mxb;
-- top;
}
}
bool ans[maxm];
int main(){
read(n);read(m);
for(int i=1;i<=m;++i){
read(e[i].u);read(e[i].v);
read(e[i].a);read(e[i].b);
}
int Q;read(Q);
for(int i=1;i<=Q;++i){
read(q[i].u);read(q[i].v);
read(q[i].a);read(q[i].b);
q[i].id = i;
}
sort(e+1,e+m+1,cmpa);sort(q+1,q+Q+1,cmpb);
int block = sqrt(m);
for(int i=1;i<=m;i+=block){
cnt = 0;
for(int j=1;j<=Q;++j){
if(q[j].a >= e[i].a && (i+block > m || e[i+block].a > q[j].a)){
tmp[++cnt] = q[j];
}
}
sort(e+1,e+i,cmpb);clear();
for(int j=1,k=1;j<=cnt;++j){
while(k < i && e[k].b <= tmp[j].b) Union(e[k++]);
top = 0;
for(int l=i;l<i+block && l <= m;++l){
if(e[l].a <= tmp[j].a && e[l].b <= tmp[j].b) Union(e[l]);
}
int x = find(tmp[j].u),y = find(tmp[j].v);
if(x == y && mxa[x] == tmp[j].a && mxb[x] == tmp[j].b) ans[tmp[j].id] = true;
Undo();
}
}
for(int i=1;i<=Q;++i) puts(ans[i] ? "Yes" : "No");
return 0;
}

其实复杂度是:\(O( m\sqrt{m}logm + q(logn+logq))\)的

最新文章

  1. golang struct扩展函数参数命名警告
  2. NuGet及快速安装使用
  3. vba 工作案例1
  4. [转] 控制Arduino的利器-Windows Remote Arduino
  5. Magicodes.WeiChat——多租户的设计与实现
  6. 无需server-U IIS7.5 在已有的多个WEB网站上配置FTP发布
  7. JAVA组程序优化综合考试试题
  8. const 常量数据,只读
  9. redis神器
  10. oninput,onpropertychange,onchange的用法和区别
  11. android 中 ColorDrawable dw = new ColorDrawable(0x3ccccccc),关于颜色定义的总结
  12. openStack 性能开测
  13. 《Java虚拟机原理图解》1.3、class文件里的訪问标志、类索引、父类索引、接口索引集合
  14. perl EXPORT模块
  15. JQuery - 点击图片显示大图
  16. Android学习-应用程序管理
  17. 常见html标签
  18. AspectJ基本用法
  19. Python数据类型-布尔/数字/字符串/列表/元组/字典/集合
  20. Spring+SpringMVC+MyBatis+easyUI整合基础篇

热门文章

  1. 虚拟化构建二分图(BZOJ2080 题解+浅谈几道双栈排序思想的题)
  2. centos7 运行postgres 数据库脚本db.sql
  3. Oracle视图传递参数
  4. linux后台开发必备技能
  5. iOS UIImage UIImageView 展示图片 不变形 处理
  6. [原创]java WEB学习笔记07:关于HTTP协议
  7. HTTPS协议原理透析
  8. BestCoder 1st Anniversary 1004 Bipartite Graph 【二分图 + bfs + 良好的逻辑思维 】
  9. 希尔排序(Shell Sort)
  10. 【转载】Dom4j的使用(全而好的文章)