4537: [Hnoi2016]最小公倍数
Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 688 Solved: 271
[ Submit][ Status][ Discuss]
Description
给定一张N个顶点M条边的无向图(顶点编号为1,2,…,n),每条边上带有权值。所有权值都可以分解成2^a*3^b
的形式。现在有q个询问,每次询问给定四个参数u、v、a和b,请你求出是否存在一条顶点u到v之间的路径,使得
路径依次经过的边上的权值的最小公倍数为2^a*3^b。注意:路径可以不是简单路径。下面是一些可能有用的定义
:最小公倍数:K个数a1,a2,…,ak的最小公倍数是能被每个ai整除的最小正整数。路径:路径P:P1,P2,…,Pk是顶
点序列,满足对于任意1<=i<k,节点Pi和Pi+1之间都有边相连。简单路径:如果路径P:P1,P2,…,Pk中,对于任意1
<=s≠t<=k都有Ps≠Pt,那么称路径为简单路径。
Input
输入文件的第一行包含两个整数N和M,分别代表图的顶点数和边数。接下来M行,每行包含四个整数u、v、a、
b代表一条顶点u和v之间、权值为2^a*3^b的边。接下来一行包含一个整数q,代表询问数。接下来q行,每行包含四
个整数u、v、a和b,代表一次询问。询问内容请参见问题描述。1<=n,q<=50000、1<=m<=100000、0<=a,b<=10^9
Output
对于每次询问,如果存在满足条件的路径,则输出一行Yes,否则输出一行 No(注意:第一个字母大写,其余
字母小写) 。
Sample Input
4 5
1 2 1 3
1 3 1 2
1 4 2 1
2 4 3 2
3 4 2 2
5
1 4 3 3
4 2 2 3
1 3 2 2
2 3 2 2
1 3 4 4
1 2 1 3
1 3 1 2
1 4 2 1
2 4 3 2
3 4 2 2
5
1 4 3 3
4 2 2 3
1 3 2 2
2 3 2 2
1 3 4 4
Sample Output
Yes
Yes
Yes
No
No
Yes
Yes
No
No
HINT
Source
#include<iostream>
#include<vector>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
#include<cmath>
using namespace std;
const int maxn = 5E4 + 50;
const int maxm = 1E5 + 10;
struct E{
int x,y,a,b; E(){}
E(int x,int y,int a,int b): x(x),y(y),a(a),b(b){}
}edgs[maxm];
bool Ecmpa(const E &A,const E &B) {return A.a < B.a;}
bool Ecmpb(const E &A,const E &B) {return A.b < B.b;}
struct Q{
int x,y,a,b,num; Q(){}
Q(int x,int y,int a,int b,int num): x(x),y(y),a(a),b(b),num(num){}
}qu[maxn];
bool Qcmpa(const Q &A,const Q &B) {return A.a < B.a;}
bool Qcmpb(const Q &A,const Q &B) {return A.b < B.b;}
struct G{
int typ,x,y,a,b,L; G(){}
G(int typ,int x,int y,int a,int b,int L): typ(typ),x(x),y(y),a(a),b(b),L(L){}
}s[maxm];
int n,q,m,cnt,top,Sqrt,fa[maxn],D[maxn],Maxa[maxn],Maxb[maxn],L[maxn],R[maxn];
bool Ans[maxn];
vector <Q> Qu[500];
int getint()
{
char ch = getchar();
int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret*10 + ch - '0',ch = getchar();
return ret;
}
void Pre_Work()
{
for (int i = 1; i <= m; i++) {
int x,y,a,b;
x = getint(); y = getint();
a = getint(); b = getint();
edgs[i] = E(x,y,a,b);
}
sort(edgs + 1,edgs + m + 1,Ecmpa);
for (int l = 1,r = Sqrt; l <= m; l += Sqrt,r += Sqrt) {
r = min(r,m); ++cnt;
L[cnt] = l; R[cnt] = r;
}
q = getint();
for (int i = 1; i <= q; i++) {
int x,y,a,b;
x = getint(); y = getint();
a = getint(); b = getint();
qu[i] = Q(x,y,a,b,i);
}
sort(qu + 1,qu + q + 1,Qcmpb);
for (int i = 1; i <= q; i++)
for (int j = cnt; j; j--)
if (edgs[L[j]].a <= qu[i].a && qu[i].a <= edgs[R[j]].a) {
Qu[j].push_back(qu[i]);
break;
}
for (int i = 1; i <= n; i++) fa[i] = i,D[i] = 1,Maxa[i] = Maxb[i] = -1;
}
int getfa(int x) {return x == fa[x]?x:getfa(fa[x]);}
void Insert(E e)
{
int fx = getfa(e.x),fy = getfa(e.y);
if (fx == fy) {
s[++top] = G(0,fx,fx,Maxa[fx],Maxb[fx],D[fx]);
Maxa[fx] = max(Maxa[fx],e.a);
Maxb[fx] = max(Maxb[fx],e.b);
}
else {
if (D[fx] >= D[fy]) swap(fx,fy);
s[++top] = G(1,fx,fy,Maxa[fy],Maxb[fy],D[fy]);
fa[fx] = fy;
Maxa[fy] = max(Maxa[fy],max(Maxa[fx],e.a));
Maxb[fy] = max(Maxb[fy],max(Maxb[fx],e.b));
D[fy] = D[fx] == D[fy]?D[fy]+1:D[fy];
}
}
void Del(int goal)
{
while (top > goal) {
G t = s[top--];
if (t.typ == 0) Maxa[t.x] = t.a,Maxb[t.x] = t.b;
else {
fa[t.x] = t.x; D[t.y] = t.L;
Maxa[t.y] = t.a,Maxb[t.y] = t.b;
}
}
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
n = getint(); m = getint(); Sqrt = sqrt(m*log2(m));
int tot = 0; Pre_Work();
for (int i = 1; i <= cnt; i++) {
//sort(Qu[i].begin(),Qu[i].end(),Qcmpb);
int now = 1; top = 0;
for (int j = 0; j < Qu[i].size(); j++) {
Q t = Qu[i][j];
while (now <= tot && edgs[now].b <= t.b) Insert(edgs[now++]);
int g = top;
for (int k = L[i]; k <= R[i]; k++)
if (edgs[k].a <= t.a) {
if (edgs[k].b <= t.b) Insert(edgs[k]);
}
else break;
int fx = getfa(t.x),fy = getfa(t.y);
if (fx == fy && Maxa[fx] == t.a && Maxb[fx] == t.b)
Ans[t.num] = 1;
else Ans[t.num] = 0;
Del(g);
}
sort(edgs + 1,edgs + R[i] + 1,Ecmpb);
tot = R[i]; Del(0);
}
for (int i = 1; i <= q; i++)
if (!Ans[i]) puts("No"); else puts("Yes");
return 0;
}