P3247-[HNOI2016]最小公倍数【分块,并查集】
生活随笔
收集整理的這篇文章主要介紹了
P3247-[HNOI2016]最小公倍数【分块,并查集】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目鏈接:https://www.luogu.com.cn/problem/P3247
題目大意
nnn個點mmm條邊,每條邊有(x,y,a,b)(x,y,a,b)(x,y,a,b)。qqq次詢問(x′,y′,a′,b′)(x',y',a',b')(x′,y′,a′,b′)表示詢問是否存在一條x′?>y′x'->y'x′?>y′的路徑使得路徑上amax=a′,bmax=b′a_{max}=a',b_{max}=b'amax?=a′,bmax?=b′
解題思路
考慮暴力的做法,我們用加入所有a≤a′a\leq a'a≤a′且b≤b′b\leq b'b≤b′的邊加入,然后看x′y′x'y'x′y′是否在同一連通塊且聯通塊中a,ba,ba,b最大值是否是a′,b′a',b'a′,b′。
如何優化,我們把所有的邊根據aia_iai?的權值分成若干個塊,對于每個塊我們把所有a′a'a′在這個范圍的內的詢問進行處理,我們把所有處理的詢問和在塊前面的邊按照bbb排序,然后這一部分我們就用指針掃描加入,對于在塊里的邊我們就暴力掃描加入。
但是每個詢問做完之后注意塊里的邊要刪去,所以我們不能用路徑壓縮,用按秩合并即可。
時間復雜度O(qmlog?n)O(q\sqrt m\log n)O(qm?logn)
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #include<cctype> #include<cmath> using namespace std; const int N=1e5+10; struct node{int x,y,a,b,s; }e[N],q[N],cl[N]; int n,m,Q,tot,p[N]; int fa[N],siz[N],A[N],B[N]; bool ans[N]; bool cmpa(node x,node y) {return x.a==y.a?(x.b<y.b):(x.a<y.a);} bool cmpb(node x,node y) {return x.b==y.b?(x.a<y.a):(x.b<y.b);} int find(int x) {return fa[x]==x?x:find(fa[x]);} int read() {int x=0,f=1; char c=getchar();while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();return x*f; } void unionn(int x,int y,int a,int b){x=find(x),y=find(y);if(siz[x]>siz[y])swap(x,y);cl[++tot]=(node){x,y,A[y],B[y],siz[y]};A[y]=max(max(A[x],A[y]),a);B[y]=max(max(B[x],B[y]),b);if(x!=y)fa[x]=y;siz[y]=max(siz[y],siz[x]+1);return; } void Clear(){for(int i=tot;i>=1;i--){fa[cl[i].x]=cl[i].x;A[cl[i].y]=cl[i].a;B[cl[i].y]=cl[i].b;siz[cl[i].y]=cl[i].s;}tot=0;return; } int main() { // freopen("multiple5.in","r",stdin); // freopen("data.out","w",stdout);n=read();m=read();for(int i=1;i<=m;i++)e[i].x=read(),e[i].y=read(),e[i].a=read(),e[i].b=read();Q=read();for(int i=1;i<=Q;i++)q[i].x=read(),q[i].y=read(),q[i].a=read(),q[i].b=read(),q[i].s=i;sort(e+1,e+1+m,cmpa);sort(q+1,q+1+Q,cmpb); int T=sqrt(m*log2(n));e[m+1].a=1e9+1;for(int k=1;k<=m;k+=T){int l=k,r=min(k+T,m);int cnt=0;for(int i=1;i<=n;i++)fa[i]=i,A[i]=B[i]=-1,siz[i]=0;for(int i=1;i<=Q;i++)if(q[i].a>=e[l].a&&q[i].a<e[r+1].a)p[++cnt]=i;if(!cnt)continue;if(k)sort(e+1,e+l,cmpb);int pt=1;for(int i=1;i<=cnt;i++){int x=p[i];while(pt<l&&e[pt].b<=q[x].b)unionn(e[pt].x,e[pt].y,e[pt].a,e[pt].b),pt++;tot=0;for(int j=l;j<=r;j++)if(e[j].a<=q[x].a&&e[j].b<=q[x].b)unionn(e[j].x,e[j].y,e[j].a,e[j].b);int fx=find(q[x].x),fy=find(q[x].y);ans[q[x].s]=((fx==fy)&&(A[fx]==q[x].a)&&(B[fx]==q[x].b));Clear();}}for(int i=1;i<=Q;i++)if(ans[i])printf("Yes\n");else printf("No\n");return 0; }總結
以上是生活随笔為你收集整理的P3247-[HNOI2016]最小公倍数【分块,并查集】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P1412-经营与开发【dp】
- 下一篇: 死而后已的已是什么意思