「HNOI2016」最小公倍数

考虑暴力,对每个询问,处理出\(\le a,\le b\)的与询问点在一起的联通块,然后判断是否是一个联通块,且联通块\(a,b\)最大值是否满足要求。

然后很显然需要去离线搞一下,考虑定期重构。

具体的,先把边按\(a\)排序,然后每\(S\)分一块。

处理每一块时,把前面所有块的边权值在这个块内的询问放在一起按\(b\)排序,这个可以用类似归并的思路\(O(n)\)完成。

然后遍历这个排序后的东西,用带权并查集维护联通性。

具体的,如果是边,就在并查集里面加上。

如果是询问,就暴力把块内的\(\le a,\le b\)的边加入并查集,然后询问,询问完了以后撤回。

做完了后对块内按\(b\)去\(sort\)一下,然后和前面的块去合并一下,到下一个块就可以归并了。

考虑复杂度,对每个块有个归并排序预处理并查集之类的是\(O(\frac{n^2}{S})\),然后对每个询问只会处理一次,复杂度是\(O(nS\log n)\)的

然后不等式一下,算出\(S=\sqrt{\frac{n}{\log n}}\)时,总复杂度\(O(n\sqrt{n\log n})\)

看起来挺美好的,我也是这么算的,但我发现取\(\sqrt n\)时是最快的??

然后想了一波,对每个块加之前的并查集应该还有个\(\log n\),总复杂度是\(O(\frac{n^2\log n}{S}+nS\log n)=O(n\sqrt n\log n)\)的,因为上界松所以才跑过去...

然而还有一个问题,如果很多个\(a\)的权值相同,你又写丑了,会对每个询问处理多次...我一开始就怎么T想了巨久


Code:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
using std::min;
using std::max;
template <class T>
void read(T &x)
{
x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
const int N=2e5+10;
struct koito_yuu
{
int u,v,a,b,op;
bool friend operator <(koito_yuu a,koito_yuu b){return a.b==b.b?a.op<b.op:a.b<b.b;}
}yuu[N],bee[N],yuy[N],tmp[N];
int n,m,q,ans[N];
bool cmp(koito_yuu a,koito_yuu b){return a.a==b.a?a.b<b.b:a.a<b.a;}
int f[N],h[N],mxa[N],mxb[N],opt[N],ds[N],dh[N],dmxa[N],dmxb[N],tim;
int Find(int x){return f[x]==x?x:Find(f[x]);}
void cop(int u,int v)
{
++tim;
opt[tim]=u,ds[tim]=v,dh[tim]=h[u],dmxa[tim]=mxa[u],dmxb[tim]=mxb[u];
}
void dcop(int t)
{
int u=opt[t];
h[u]=dh[t],mxa[u]=dmxa[t],mxb[u]=dmxb[t],f[ds[t]]=ds[t];
}
void Merge(int u,int v,int a,int b)
{
u=Find(u),v=Find(v);
if(u==v)
{
cop(u,0);
mxa[u]=max(mxa[u],a);
mxb[u]=max(mxb[u],b);
return;
}
if(h[u]<h[v]) std::swap(u,v);
cop(u,v);
f[v]=u;
mxa[u]=max(max(mxa[u],a),mxa[v]);
mxb[u]=max(max(mxb[u],b),mxb[v]);
if(h[u]==h[v]) ++h[u];
}
int main()
{
read(n),read(m);
for(int i=1;i<=m;i++)
{
read(yuu[i].u),read(yuu[i].v);
read(yuu[i].a),read(yuu[i].b);
}
read(q);
for(int i=1;i<=q;i++)
{
read(bee[i].u),read(bee[i].v);
read(bee[i].a),read(bee[i].b);
bee[i].op=i;
}
std::sort(yuu+1,yuu+1+m,cmp);
std::sort(bee+1,bee+1+q);
int B=sqrt(m/log2(n))+1,T=(m-1)/B+1;
for(int k=1;k<=T;k++)
{
int L=B*(k-1)+1,R=min(B*k,m),l1=1,r1=L-1,l2=1,r2=0;
for(int i=1;i<=q;i++)
if(yuu[L].a<=bee[i].a&&(R==m||bee[i].a<yuu[R+1].a))
tmp[++r2]=bee[i];
int cnt=0;
while(l1<=r1&&l2<=r2)
{
if(yuu[l1]<tmp[l2]) yuy[++cnt]=yuu[l1++];
else yuy[++cnt]=tmp[l2++];
}
while(l2<=r2) yuy[++cnt]=tmp[l2++];
for(int i=1;i<=n;i++) f[i]=i,mxa[i]=mxb[i]=-1,h[i]=1;
for(int i=1;i<=cnt;i++)
{
int u=yuy[i].u,v=yuy[i].v,a=yuy[i].a,b=yuy[i].b;
if(yuy[i].op)
{
tim=0;
for(int j=L;j<=R;j++)
if(yuu[j].a<=a&&yuu[j].b<=b)
Merge(yuu[j].u,yuu[j].v,yuu[j].a,yuu[j].b);
int ru=Find(u),rv=Find(v);
ans[yuy[i].op]=(ru==rv)&&(mxa[ru]==a)&&(mxb[ru]==b);
for(int j=tim;j;j--) dcop(j);
}
else Merge(u,v,a,b);
}
std::sort(yuu+L,yuu+R+1);
l1=1,r1=L-1,l2=L,r2=R,cnt=0;
while(l1<=r1&&l2<=r2)
{
if(yuu[l1]<yuu[l2]) tmp[++cnt]=yuu[l1++];
else tmp[++cnt]=yuu[l2++];
}
while(l1<=r1) tmp[++cnt]=yuu[l1++];
while(l2<=r2) tmp[++cnt]=yuu[l2++];
for(int i=1;i<=cnt;i++) yuu[i]=tmp[i];
}
for(int i=1;i<=q;i++) puts(ans[i]?"Yes":"No");
return 0;
}

2019.3.7

「HNOI2016」最小公倍数 解题报告的更多相关文章

  1. 「HNOI2016」树 解题报告

    「HNOI2016」树 事毒瘤题... 我一开始以为每次把大树的子树再接给大树,然后死活不知道咋做,心想怕不是个神仙题哦 然后看题解后才发现是把模板树的子树给大树,虽然思维上难度没啥了,但是还是很难写 ...

  2. 「HNOI2016」序列 解题报告

    「HNOI2016」序列 有一些高妙的做法,懒得看 考虑莫队,考虑莫队咋移动区间 然后你在区间内部找一个最小值的位置,假设现在从右边加 最小值左边区间显然可以\(O(1)\),最小值右边的区间是断掉的 ...

  3. 「HNOI2016」网络 解题报告

    「HNOI2016」网络 我有一个绝妙的可持久化树套树思路,可惜的是,它的空间是\(n\log^2 n\)的... 注意到对一个询问,我们可以二分答案 然后统计经过这个点大于当前答案的路径条数,如果这 ...

  4. 「ZJOI2016」旅行者 解题报告

    「ZJOI2016」旅行者 对网格图进行分治. 每次从中间选一列,然后枚举每个这一列的格子作为起点跑最短路,进入子矩形时把询问划分一下,有点类似整体二分 至于复杂度么,我不会阿 Code: #incl ...

  5. 「HAOI2018」染色 解题报告

    「HAOI2018」染色 是个套路题.. 考虑容斥 则恰好为\(k\)个颜色恰好为\(c\)次的贡献为 \[ \binom{m}{k}\sum_{i\ge k}(-1)^{i-k}\binom{m-k ...

  6. 「SCOI2016」围棋 解题报告

    「SCOI2016」围棋 打CF后困不拉基的,搞了一上午... 考虑直接状压棋子,然后发现会t 考虑我们需要上一行的状态本质上是某个位置为末尾是否可以匹配第一行的串 于是状态可以\(2^m\)压住了, ...

  7. 「SCOI2016」妖怪 解题报告

    「SCOI2016」妖怪 玄妙...盲猜一个结论,然后过了,事后一证,然后假了,数据真水 首先要最小化 \[ \max_{i=1}^n (1+k)x_i+(1+\frac{1}{k})y_i \] \ ...

  8. 「SCOI2016」美味 解题报告

    「SCOI2016」美味 状态极差无比,一个锤子题目而已 考虑每次对\(b\)和\(d\)求\(c=d \ xor \ (a+b)\)的最大值,因为异或每一位是独立的,所以我们可以尝试按位贪心. 如果 ...

  9. 「SCOI2016」萌萌哒 解题报告

    「SCOI2016」萌萌哒 这思路厉害啊.. 容易发现有个暴力是并查集 然后我想了半天线段树优化无果 然后正解是倍增优化并查集 有这个思路就简单了,就是开一个并查集代表每个开头\(i\)每个长\(2^ ...

随机推荐

  1. ocrosoft 1015 习题1.22 求一元二次方程a*x^2 + b*x + c = 0的根

    http://acm.ocrosoft.com/problem.php?id=1015 题目描述 求一元二次方程a*x2 + b*x + c = 0的根.系数a.b.c为浮点数,其值在运行时由键盘输入 ...

  2. xmanager 乱码

    xmanager连接后中文显示乱码 - 程序员CC - 博客园http://www.cnblogs.com/aomidata/p/3445075.html Xshell 为什么会出现中文乱码?-Xma ...

  3. CentOS 7 安装配置带用户认证的squid代理服务器

    这里只简述搭建一个带用户认证的普通代理 一.安装 安装过程十分简便,只需要安装一下squid,一条命令搞定 yum install squid rpm -qa | grep squid squid-- ...

  4. hangfire使用笔记

    1.导入nuget包 2.配置 简单配置后就可以写自己的Job了 注意:Hangfire.RecurringJobExtensions这个扩展支持两种job添加方法:json配置文件和特性.但由于时区 ...

  5. mysql异常:Packet for query is too large (10240 > 1024). You can change this value

    出现这个问题的原因是:mysql的配置文件中 max_allowed_packet 设置过小,mysql根据配置文件会限制server接受的数据包大小. 还有人会说我操作的数据量明显没有超过这个值为啥 ...

  6. idea 最新破解亲测有效

    选择License serverLicense server address: 填:http://active.chinapyg.com/ (不能用了) 2018-5-7更新 新增一个 http:// ...

  7. Artifact project04:war :Error during artifact deployment. See server log for details

    困扰了我好长时间,我的错误是 先 Run clean  再package就成功了.

  8. 解决mybatis generator警告Cannot obtain primary key information from the database, generated objects may be incomplete

    使用 mybatis generator 生成pojo.dao.mapper时 经常出现 Cannot obtain primary key information from the database ...

  9. java数据库导入excel数据

    导入数据会将表格分为xls和xlsx两种格式,网上有很多案例 1.excel数据表中的数据不全,数据库中又是必填选项:---从sql语句入手:判断有无 来改变语句 //设置可有可无 字段 加一个必有字 ...

  10. openwrt-scripts/config/mconf: Syntax error: “(” unexpected错误解决

    scripts/config/mconf: Syntax error: “(” unexpected错误解决 从其他地方复制而来的openwrt SDK,放在本地执行make menuconfig时出 ...