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 的比赛变化挺大的,有部分分了,而且不再是固定十个点了(部分分只说这几个点满足这几个性质,以为十个点的我还高兴了一会,一提交,...),除此之外居然赛后还排名了.这 ...
随机推荐
- IP 层收发报文简要剖析2--ip报文的输入ip_local_deliver
ip报文根据路由结果:如果发往本地则调用ip_local_deliver处理报文:如果是转发出去,则调用ip_forward 处理报文. 一.ip报文转发到本地: /* * Deliver IP Pa ...
- 信号发送接收函数:sigqueue/sigaction
信号是一种古老的进程间通信方式,下面的例子利用sigqueue发送信号并附带数据:sigaction函数接受信号并且处理时接受数据. 1.sigqueue: 新的信号发送函数,比kill()函数传递了 ...
- 五:request和response的使用
接着上一篇我们在搞完servlet的终极模式之后,接着就需要对发送的请求做出响应了 在这里,所谓的响应,都是返回页面的语言在浏览器上显示也就是HTML语言,所以返回的结果只有HTML语言才能在浏览器上 ...
- SQL SERVER中 DBLINK的实现
不同服务器数据库之间的数据操作 --创建链接服务器 exec sp_addlinkedserver'ITSV' ,'' , 'SQLOLEDB' ,'远程服务器名或ip地址' exec sp_addl ...
- android下vulkan与opengles纹理互通
先放demo源码地址:https://github.com/xxxzhou/aoce 06_mediaplayer 效果图: 主要几个点: 用ffmpeg打开rtmp流. 使用vulkan Compu ...
- 这个厉害了,阿里P7大佬都在看的SpringCloud 总结,帮你梳理全部知识点!
微服务 微服务架构是一种以一些微服务来替代开发单个大而全应用的方法,每一个小服务运行在自己的进程里,并以轻量级的机制来通信, 通常是 HTTP RESTful API.微服务强调小快灵, 任何一个相对 ...
- 利用perspective 和 transform 里面的几个参数来实现旋转照片墙
旋转照片墙 首先,来看下,是什么效果吧,上效果图 ↓ 其实这个东西,很容易制作,先说下思路, 把照片都给叠在一起,然后 rotateY 旋转,给每张图片 旋转不一样的角度能构成一圈, 然后transl ...
- 设置searchDisplayController的searchResultsTableView的UITableViewStyle为grouped
[self.searchDisplayController setValue:[NSNumber numberWithInt:UITableViewStyleGrouped] forKey:@&quo ...
- 分析一个免杀webshell发现的php特性
文章首发于t00ls,嫌文章太啰嗦的可以直接看结论 起源 之前看到别人分享的一个免杀webshell: <?php @$GLOBALS{next} = $GLOBALS[$GLOBALS[fun ...
- 【CF600E】Lomsat gelral——树上启发式合并
(题面来自luogu) 题意翻译 一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. ci <= n <= 1e5 裸题.统计时先扫一遍得到出 ...