P5838 [USACO19DEC]Milk Visits G
发现是一道比较裸的树上莫队,于是就开始刚,然后发现好像是最难的一道题……(本题解用于作者加深算法理解,也欢迎各位的阅读)
题意
给你一棵树,树有点权,询问一条路径上是否有点权为 \(c\) 的点。
题解
我们可以比较明显地发现询问是很像莫队的询问处理的,可以 \(O(1)\) 去扩展 \(l\) 和 \(r\) 。但是这题是树,所以我们需要引入欧拉序的概念。
欧拉序其实很像 \(dfs\) 序,但是会在出栈的时候多记录一次,我们可以利用欧拉序来将树上的路径转化为莫队需要的区间问题。
我们可以先画一张图:
其中位于节点右侧的是入栈时间,位于节点左侧的是出栈时间。
我们不妨以每一个点的入栈时间为编号,欧拉序则为:
\]
比如对于 \(9\) ~ \(16\) 这一条路径,我们可以用时间 \(10\) ~ \(16\) 来表示,其中出现两次的点我们不进行计算,并且还需要多加上 \(9\) 和 \(16\) 的 \(lca\):\(1\) ,这些可以用异或运算和特判来解决。即路径 \(x\) ~ \(y\):\(lst_x\) ~ \(fir_y\) 。
同时我们可以发现,如果路径上的点是为祖先关系,我们需要特殊处理,可以发现是 \(fir_x\) ~ \(fir_y\) 。
因此我们将所有的路径都转化为区间之后就可以用莫队离线实现了,复杂度 \(O(n\sqrt n)\) 。可是不开 \(O2\) 过不了……
以上。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,M=1e5+5;
int n,m,type[N];
struct Edge{int nxt,to;}e[N<<1];int head[N];
void add(int u,int v,int i){e[i]=Edge{head[u],v},head[u]=i;}
int fir[N],lst[N],dfn[N<<1],cnt_dfn=0;
int dep[N],fa[N][25];
void dfs(int u)
{
dfn[++cnt_dfn]=u,fir[u]=cnt_dfn;
for(int i=head[u];i;i=e[i].nxt)
{
if(e[i].to==fa[u][0]) continue;
fa[e[i].to][0]=u;
dep[e[i].to]=dep[u]+1;
dfs(e[i].to);
}
dfn[++cnt_dfn]=u,lst[u]=cnt_dfn;
}
int lca(int u,int v)
{
if(dep[u]>dep[v]) swap(u,v);
for(int i=20;i>=0;--i)
{
if(dep[fa[v][i]]>=dep[u])
v=fa[v][i];
}
if(u==v) return u;
for(int i=20;i>=0;--i)
{
if(fa[u][i]!=fa[v][i])
u=fa[u][i],v=fa[v][i];
}
return fa[u][0];
}
struct Query{int l,r,lca,c,id;}q[M];
int bel[N<<1],size;
bool cmp(Query a,Query b)
{
if(bel[a.l]^bel[b.l]) return bel[a.l]<bel[b.l];
if(bel[a.l]^1) return a.r<b.r;
return a.r>b.r;
}
int l=1,r=0,tag[N],cnt[N],ans[M];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;++i) scanf("%d",&type[i]);
for(int i=1,u,v;i<n;++i)
{
scanf("%d%d",&u,&v);
add(u,v,i<<1);
add(v,u,i<<1|1);
}
dep[1]=1,dfs(1);
for(int i=1;i<=20;++i)
{
for(int j=1;j<=n;++j)
fa[j][i]=fa[fa[j][i-1]][i-1];
}
size=sqrt(n*2);
for(int i=1,cnt=0;i<=n*2;i+=size)
{
++cnt;
for(int j=i;j<min(i+size,n*2+1);++j)
bel[j]=cnt;
}
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].c),q[i].id=i;
if(fir[q[i].l]>fir[q[i].r]) swap(q[i].l,q[i].r);
q[i].lca=lca(q[i].l,q[i].r);
if(q[i].lca==q[i].l) q[i].l=fir[q[i].l];
else q[i].l=lst[q[i].l];
q[i].r=fir[q[i].r];
}
// for(int i=1;i<=n*2;++i)
// printf("%d ",dfn[i]);
// printf("\n");
sort(q+1,q+1+m,cmp);
// for(int i=1;i<=m;++i)
// printf("%d %d %d\n",q[i].l,q[i].r,q[i].lca);
for(int i=1;i<=m;++i)
{
while(q[i].r>r)
{
tag[dfn[++r]]^=1;
if(tag[dfn[r]]) cnt[type[dfn[r]]]++;
else cnt[type[dfn[r]]]--;
}
while(q[i].r<r)
{
tag[dfn[r]]^=1;
if(tag[dfn[r]]) cnt[type[dfn[r--]]]++;
else cnt[type[dfn[r--]]]--;
}
while(q[i].l>l)
{
tag[dfn[l]]^=1;
if(tag[dfn[l]]) cnt[type[dfn[l++]]]++;
else cnt[type[dfn[l++]]]--;
}
while(q[i].l<l)
{
tag[dfn[--l]]^=1;
if(tag[dfn[l]]) cnt[type[dfn[l]]]++;
else cnt[type[dfn[l]]]--;
}
// printf("$$$%d %d\n",l,r);
// for(multiset<int>::iterator i=st.begin();i!=st.end();++i)
// printf("%d ",*i);
// printf("\n");
ans[q[i].id]=(cnt[q[i].c]||type[q[i].lca]==q[i].c);
}
for(int i=1;i<=m;++i) printf("%d",ans[i]);
printf("\n");
return 0;
}
P5838 [USACO19DEC]Milk Visits G的更多相关文章
- 【题解】[USACO19DEC]Milk Visits G
题目戳我 \(\text{Solution:}\) 这题不要把思想局限到线段树上--这题大意就是求路径经过的值中\(x\)的出现性问题. 最开始的想法是值域线段树--看了题解发现直接\(vector\ ...
- P5836 [USACO19DEC]Milk Visits S 从并查集到LCA(最近公共祖先) Tarjan算法 (初级)
为什么以它为例,因为这个最水,LCA唯一黄题. 首先做两道并查集的练习(估计已经忘光了).简单来说并查集就是认爸爸找爸爸的算法.先根据线索理认爸爸,然后查询阶段如果发现他们的爸爸相同,那就是联通一家的 ...
- 洛谷 P5837 [USACO19DEC]Milk Pumping G (单源最短路,dijkstra)
题意:有一\(n\)个点,\(m\)条边的双向图,每条边都有花费和流量,求从\(1\)~\(n\)的路径中,求\(max\frac{min(f)}{\sum c}\). 题解:对于c,一定是单源最短路 ...
- P5837 [USACO19DEC]Milk Pumping G
题目描述 Farmer John 最近为了扩张他的牛奶产业帝国而收购了一个新的农场.这一新的农场通过一个管道网络与附近的小镇相连,FJ 想要找出其中最合适的一组管道,将其购买并用来将牛奶从农场输送到小 ...
- Milk Pumping G&Milk Routing S 题解
Milk Pumping G&Milk Routing S 双倍经验时间 洛谷P5837 [USACO19DEC]Milk Pumping G 洛谷P3063 [USACO12DEC]Milk ...
- 题解 P5837 【[USACO19DEC]Milk Pumping】
这题其实想法挺简单的,因为他只需要简单的把每个点的花费和流量用dp记下来就好了 1.怎么记: 首先考虑dp的状态.由于所在的点和流量都要记,所以dp开二维,一维记所在的点,另一维记去哪 //dp[i] ...
- 2021record
2021-10-14 P2577 [ZJOI2004]午餐 2021-10-13 CF815C Karen and Supermarket(小小紫题,可笑可笑) P6748 『MdOI R3』Fall ...
- USACO19DEC题解
Bronze A Cow Gymnastics 题目:https://www.luogu.com.cn/problem/P5831 题解:用数组存一下出现位置,O(n^2)枚举一下就好. 代码: #i ...
- USACO 2019 December Contest 随记
Forewords 今年 USACO 的比赛变化挺大的,有部分分了,而且不再是固定十个点了(部分分只说这几个点满足这几个性质,以为十个点的我还高兴了一会,一提交,...),除此之外居然赛后还排名了.这 ...
随机推荐
- 154. Find Minimum in Rotated Sorted Array II(循环数组查找)
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e. ...
- 调度器简介,以及Linux的调度策略(转)
进程是操作系统虚拟出来的概念,用来组织计算机中的任务.但随着进程被赋予越来越多的任务,进程好像有了真实的生命,它从诞生就随着CPU时间执行,直到最终消失.不过,进程的生命都得到了操作系统内核的关照.就 ...
- kernel——Makefile, head.S ...
在Makefile中找到的重要信息: (1)连接脚本 通过连接脚本,知道的信息: (1)入口符号 stext (2)入口连接地址 0xC0000000 + 0x00008000 根据入口符号,可以找到 ...
- 预估ceph的迁移数据量
引言 我们在进行 ceph 的 osd 的增加和减少的维护的时候,会碰到迁移数据,但是我们平时会怎么去回答关于迁移数据量的问题,一般来说,都是说很多,或者说根据环境来看,有没有精确的一个说法,到底要迁 ...
- python 学习代码
1 #-- 寻求帮助: 2 dir(obj) # 简单的列出对象obj所包含的方法名称,返回一个字符串列表 3 help(obj.func) # 查询obj.func的具体介绍和用法 4 5 #-- ...
- Rest语法,传入多个参数
Rest语法,传入多个参数 js调用函数时可以传入任意数量的参数,而不报错.如果传入的参数没有用到,那么传入多余的参数没有任何用处,那不是瞎子点灯白费蜡嘛.为了充分利用传入的每一个参数,我们可以采用R ...
- 分布式监控系统之Zabbix主动、被动及web监控
前文我们了解了zabbix的网络发现功能,以及结合action实现自动发现主机并将主机添加到zabbix hosts中,链接指定模板进行监控:回顾请参考https://www.cnblogs.com/ ...
- Guitar Pro的10个非常实用的技巧(下)
Guitar Pro 7具有许多功能和编辑选项,只需点击几下即可随时创建与编辑我们的乐谱,.以下就为大家介绍10个Guitar Pro中实用的技巧,可以大大的节省我们的时间. 上次在<Guita ...
- 如何灵活运用ABBYY FineReader的识别功能
由于工作的原因,经常会使用到文字识别工具,说真的,一款好用的文字识别工具能省不少事,前不久碰到一位职场新人,他的工作内容也离不开文字识别工具,他还问我有什么好用的软件推荐,说到好用,还是ABBYY F ...
- HMM、CTC、RNN-T训练是所有alignment的寻找方法
1.1 LAS产生label的计算 LAS是可以看做能够直接计算给定一段acoustic feature时输出token sequences的概率,即\(p(Y|X)\),LAS每次给定一个aco ...