[HNOI2016]最小公倍数

题意

给你一张图,每条边有两个权值 a,b a , b

每次询问是否存在一个 uv u → v 的路径,满足 max{a}=A,max{b}=B m a x { a } = A , m a x { b } = B


写在前面

对于这种有两种限制的题目

一般的套路就是条件按照第一种权值为关键字排序,询问按照第二种关键字排序

然后给条件分块,然后对于一个块只把第一关键字符合条件的询问放进去

在把当前块前面的点按照第二关键字排序

这样当前块前面的点都是符合当前询问点对于第一关建字条件的

而且第二关键字都是单调的,所以就可以 twopointer t w o − p o i n t e r 扫一下

然后对于每个询问,暴力处理一下当前块的贡献


题解

考虑这道题,可以看出只有边权 aA,bB a ≤ A , b ≤ B 的边才有用

一个简单的想法就是把所有满足条件的边加进去,然后用并查集判断两点是否联通,并且联通块内最大值是否合法

根据上面说的我们可以把边按照 a a 从小到大排序,询问按照b从小到大排序

对于一个块 [i,i+Size] [ i , i + S i z e ] 我们把询问的 A A [vala[i],vala[i+Size])之间的询问放进去

然后把 [1,i) [ 1 , i ) 的边按照 b b 从小到大排序,twopointer边扫边加边(用并查集维护连通性和最大值)

对于一个询问暴力把 [i,i+Size) [ i , i + S i z e ) 内满足 valaA,valbB v a l a ≤ A , v a l b ≤ B 的边加进去

然后用并查集判断是否合法

处理完一个询问后再暴力把这些边删掉

所以并查集不能路径压缩,而且还要用一个桶子把这些边都存下(存联通块合并前的状态)

这种写法当 Size=mlogn S i z e = m log ⁡ n 时最优手玩出来的

#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
    char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
    while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
const int N=1e5+5;
typedef int arr[N];
struct eg{
    int u,v,a,b,k;
    inline void in(){sd(u),sd(v),sd(a),sd(b);}
}a[N],b[N],c[N],d[N];
int n,m,q,Top;arr fa,sz,Am,Bm,ans;
inline bool cpa(const eg a,const eg b){return a.a==b.a?a.b<b.b:a.a<b.a;}
inline bool cpb(const eg a,const eg b){return a.b==b.b?a.a<b.a:a.b<b.b;}
int gf(int x){return fa[x]==x?x:gf(fa[x]);}
inline void merge(int u,int v,int a,int b){
    u=gf(u),v=gf(v);if(sz[u]>sz[v])swap(u,v);
    d[++Top]={u,v,Am[v],Bm[v],sz[v]};
    if(u^v)fa[u]=v,sz[v]+=sz[u],
        cmax(Am[v],Am[u]),cmax(Bm[v],Bm[u]);
    cmax(Am[v],a),cmax(Bm[v],b);
}
int main(){
    #ifndef ONLINE_JUDGE
        file("s");
    #endif
    sd(n),sd(m);
    fp(i,1,m)a[i].in();
    sd(q);
    fp(i,1,q)b[i].in(),b[i].k=i;
    sort(a+1,a+m+1,cpa);sort(b+1,b+q+1,cpb);
    register int Sz=sqrt(m*log2(n)),i,j,k,l;
    for(i=1;i<=m;i+=Sz){
        fp(j,1,n)fa[j]=j,Am[j]=Bm[j]=-1,sz[j]=1;
        int Sum=0;
        fp(j,1,q)if(a[i].a<=b[j].a&&
            (b[j].a<a[i+Sz].a||i+Sz>m))c[++Sum]=b[j];
        if(!Sum)continue;if(i^1)sort(a+1,a+i,cpb);
        for(j=k=1;j<=Sum;++j){
            for(;k<i&&a[k].b<=c[j].b;++k)
                merge(a[k].u,a[k].v,a[k].a,a[k].b);
            Top=0;
            for(l=i;l<i+Sz&&l<=m;++l)
                if(a[l].a<=c[j].a&&a[l].b<=c[j].b)
                    merge(a[l].u,a[l].v,a[l].a,a[l].b);
            int u=gf(c[j].u),v=gf(c[j].v);
            ans[c[j].k]=(u==v&&Am[u]==c[j].a&&Bm[u]==c[j].b);
            fd(l,Top,1){
                u=d[l].u,v=d[l].v;fa[u]=u;
                Am[v]=d[l].a,Bm[v]=d[l].b,sz[v]=d[l].k;
            }Top=0;
        }
    }
    fp(i,1,q)puts(ans[i]?"Yes":"No");
return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的描述,题目中的影魔拥有n个灵魂,每个灵魂有一个战斗力ki。对于任意一对灵魂对i,j (i<j),如果不存在ks (i<s<j)大于ki或者kj,则会为影魔提供p1的攻击力。另一种情况是,如果存在一个位置k,满足ki<c<kj或者kj<c<ki,则会为影魔提供p2的攻击力。其他情况下的灵魂对不会为影魔提供攻击力。 根据引用\[3\]的描述,我们可以从左到右进行枚举。对于情况1,当扫到r\[i\]时,更新l\[i\]的贡献。对于情况2.1,当扫到l\[i\]时,更新区间\[i+1,r\[i\]-1\]的贡献。对于情况2.2,当扫到r\[i\]时,更新区间\[l\[i\]+1,i-1\]的贡献。 因此,对于给定的区间\[l,r\],我们可以根据上述方法计算出区间内所有下标二元组i,j (l<=i<j<=r)的贡献之和。 #### 引用[.reference_title] - *1* *3* [P3722 [AH2017/HNOI2017]影魔(树状数组)](https://blog.csdn.net/li_wen_zhuo/article/details/115446022)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [洛谷3722 AH2017/HNOI2017 影魔 线段树 单调栈](https://blog.csdn.net/forever_shi/article/details/119649910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值