[BZOJ 4537][Hnoi 2016]最小公倍数

传送门

并查集+分块

看到题目可以想到暴力做法,

对于每个询问,

将所有a和b小于等于询问值的的边加入图中(用并查集),

如果询问的u和v在一个联通块中,

且该联通块的maxa和maxb均等与询问的a和b,

则答案为Yes。

显然暴力是过不了的,于是可以用分块。

 

将所有边按a值升序排序,分成√m 块操作,

设每块第一条边为sp,每块长度为len,

每次操作将edge[sp].a<=a<edge[sp+len].a的询问加入询问序列,

将询问序列按b升序排列。

对于边可以分成两部分:

 

  1、当前块之前的边;

  2、当前块的边;

 

对于第一部分的边,其a值必定小于等于当前询问序列中的a值,

所以按b升序排序后只要边的b值小于等于询问的b值就可以加进图中,

这一部分的边加入后在处理下一个分块的询问之前都不用删(因为询问和边按b升序排序了);

 

对于第二部分的边,暴力加上暴力删就可以了。

至于如何暴力,开个栈把操作都记录下来就可以了。

 

代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 
  4 using namespace std;
  5 
  6 #define N ((1<<16)-1)
  7 #define M ((1<<17)-1)
  8 #define Q ((1<<16)-1)
  9 
 10 int n,m,ep[M],qp[Q],ans[Q],q;
 11 
 12 struct E{
 13     int u,v,a,b;
 14     inline void read(){scanf("%d%d%d%d",&u,&v,&a,&b);}
 15 }e[M],que[Q];
 16 
 17 
 18 struct ACT_stack{
 19     int *pos[N],val[N],top;
 20     inline void push(int*p){pos[top]=p;val[top]=*p;top++;}
 21     inline void clear(){while (top) *pos[--top]=val[top];}
 22 }act;
 23 
 24 struct Union_Find_sets{
 25     int fa[N],dep[N],va[N],vb[N];
 26     int root(int x){return fa[x]==x?x:root(fa[x]);}
 27     inline void initialize(){for (int i=0;i<=n;i++)fa[i]=i,dep[i]=1,va[i]=-1,vb[i]=-1;}
 28     inline void merge(E&e,bool yes)
 29     {
 30         int x=root(e.u),y=root(e.v),tmp;
 31         if (x!=y)
 32         {
 33             if (dep[x]==dep[y])
 34             {
 35                 if (yes) act.push(&dep[x]);
 36                 dep[x]++;
 37             }
 38             if (dep[x]<dep[y]) swap(x,y);
 39             if (yes) act.push(&fa[y]);
 40             fa[y]=x;
 41         }
 42         tmp=max(va[y],e.a);
 43         if (tmp>va[x])
 44         {
 45             if (yes) act.push(&va[x]);
 46             va[x]=tmp;    
 47         }
 48         tmp=max(vb[y],e.b);
 49         if (tmp>vb[x])
 50         {
 51             if (yes) act.push(&vb[x]);
 52             vb[x]=tmp;    
 53         }
 54     }
 55 }ufs;
 56 
 57 void putin()
 58 {
 59     int i;
 60     scanf("%d%d",&n,&m);
 61     for (i=0;i<m;i++) {e[i].read();ep[i]=i;}
 62     scanf("%d",&q);
 63     for (i=0;i<q;i++) que[i].read();
 64 }
 65 
 66 inline bool cmp1(const E&a,const E&b){return a.a<b.a;}
 67 inline bool cmp2(int a,int b){return e[a].b<e[b].b;}
 68 inline bool cmp3(int a,int b){return que[a].b<que[b].b;}
 69 
 70 void answer()
 71 {
 72     int sp,i,j,ne,cnt,len=1,x,y;
 73     sort(e,e+m,cmp1);
 74     while (len*len<m)len++;
 75     for (sp=0;sp<m;sp+=len)
 76     {
 77         cnt=0;
 78         for (i=0;i<q;i++) 
 79             if (que[i].a>=e[sp].a&&(sp+len>=m||que[i].a<e[sp+len].a)) {qp[cnt++]=i;}
 80         if (!cnt) continue;
 81         sort(ep,ep+sp,cmp2);
 82         sort(qp,qp+cnt,cmp3);
 83         ufs.initialize();
 84         for (i=ne=0;i<cnt;i++)
 85         {
 86             while (ne<sp&&e[ep[ne]].b<=que[qp[i]].b)
 87                 ufs.merge(e[ep[ne++]],0);
 88             for (j=sp;j<min(sp+len,m);j++)
 89                 if (e[j].a<=que[qp[i]].a&&e[j].b<=que[qp[i]].b)
 90                     ufs.merge(e[j],1);
 91             x=ufs.root(que[qp[i]].u);
 92             y=ufs.root(que[qp[i]].v);
 93             if (x==y&&ufs.va[x]==que[qp[i]].a&&ufs.vb[x]==que[qp[i]].b) ans[qp[i]]=1;
 94             act.clear();
 95         }
 96     }    
 97     for (i=0;i<q;i++)
 98         printf(ans[i]?"Yes\n":"No\n");
 99 }
100 
101 int main()
102 {
103 //    freopen("multiple.in","r",stdin);
104 //    freopen("multiple.out","w",stdout);
105     putin();
106     answer();
107 //    fclose(stdin);
108 //    fclose(stdout);
109 }
multiple

 

posted @ 2016-04-25 16:54  KaNNe乄羽  阅读(359)  评论(1编辑  收藏  举报