Milk Visits G
Milk Visits G
题意
给定一棵
数据范围:
解法
专门来写一篇题解,特别是现在已经困得不行的时候写一篇题解,是为了复习一个知识点,就是对于互相独立的询问进行离散化处理。昨天考试三道题有两道都是离线加数据结构,那再练习一道离线题目也显得十分必要了。
树上路径,想到用树链剖分,但普通树链剖分(或者说普通线段树)无法维护如此多的信息,再加上这些询问本身互相独立(因为无后效性且不带修改),于是想到离线求解。
怎么离线?个人理解就是把有相同部分的问题放到一起集中处理或者按顺序处理。应用到本题就是把那些
但很明显,这样会超时。于是考虑一下这个算法复杂度高在哪里,经过观察发现它复杂度高在重新建树部分,那下一步就可以思考,真的有必要重新建树吗,或者说咱能不能在已有的那棵线段树上进行修改呢?
答案是可以的。考虑将查询按
这样一来,问题就明朗得多了。总结一下,我们应该先把所有点权小于等于当前询问
复杂度
我觉得我已经讲得比较清楚了,代码实现应该不算太难吧。
放上我丑陋的代码。AC记录
#include<cstdio>
#include<algorithm>
//#define zczc
using namespace std;
const int N=100010;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
wh*=f;return;
}
inline int max(int s1,int s2){
return s1<s2?s2:s1;
}
inline void swap(int &s1,int &s2){
int s3=s1;s1=s2;s2=s3;return;
}
int m,n;
struct inf{
int wh,data;
}a[N];
inline bool cmpinf(inf s1,inf s2){
return s1.data<s2.data;
}
struct edge{
int t,next;
}e[N<<1];
int head[N],esum;
inline void add(int fr,int to){
esum++;
e[esum].t=to;
e[esum].next=head[fr];
head[fr]=esum;
return;
}
struct ask{
int wh,s1,s2,val;
}q[N];
inline bool cmpask(ask s1,ask s2){
return s1.val<s2.val;
}
int f[N],d[N],size[N],son[N];
void dfs1(int wh,int fa,int deep){
f[wh]=fa;d[wh]=deep;size[wh]=1;
int bigson=0;
for(int i=head[wh],th;i;i=e[i].next){
th=e[i].t;
if(th==fa)continue;
dfs1(th,wh,deep+1);
size[wh]+=size[th];
if(size[th]>bigson){
bigson=size[th];son[wh]=th;
}
}
return;
}
int cnt,id[N],s[N],top[N];
void dfs2(int wh,int fa,int ntop){
id[wh]=++cnt;s[cnt]=wh;top[wh]=ntop;
if(son[wh])dfs2(son[wh],wh,ntop);
for(int i=head[wh],th;i;i=e[i].next){
th=e[i].t;
if(th==fa||th==son[wh])continue;
dfs2(th,wh,th);
}
return;
}
#define lc (wh<<1)
#define rc (wh<<1|1)
#define mid (t[wh].l+t[wh].r>>1)
struct node{
int l,r,data;
}t[N<<2];
inline void pushup(int wh){
t[wh].data=max(t[lc].data,t[rc].data);
return;
}
void build(int wh,int l,int r){
t[wh].l=l,t[wh].r=r,t[wh].data=0;
if(l==r)return;
build(lc,l,mid);
build(rc,mid+1,r);
return;
}
void change(int wh,int pl,int val){
if(t[wh].l==t[wh].r){
t[wh].data=max(t[wh].data,val);
return;
}
if(pl<=mid)change(lc,pl,val);
else change(rc,pl,val);
pushup(wh);
return;
}
int work(int wh,int wl,int wr){
if(wl<=t[wh].l&&t[wh].r<=wr){
return t[wh].data;
}
int an=0;
if(wl<=mid)an=max(an,work(lc,wl,wr));
if(wr>mid)an=max(an,work(rc,wl,wr));
return an;
}
#undef lc
#undef rc
#undef mid
bool ans[N];
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
read(m);read(n);
for(int i=1;i<=m;i++){
read(a[i].data);
a[i].wh=i;
}
sort(a+1,a+m+1,cmpinf);
int s1,s2;
for(int i=1;i<m;i++){
read(s1);read(s2);
add(s1,s2);add(s2,s1);
}
for(int i=1;i<=n;i++){
read(q[i].s1);read(q[i].s2);read(q[i].val);q[i].wh=i;
}
sort(q+1,q+n+1,cmpask);
dfs1(1,0,1);
dfs2(1,0,1);
build(1,1,m);
int now=1;
//for(int i=1;i<=m;i++)printf("%d\n",d[i]);
for(int i=1;i<=n;i++){
while(now<=m&&a[now].data<=q[i].val){
//printf("working");
change(1,id[a[now].wh],a[now].data);
now++;
}
int an=0;
s1=q[i].s1,s2=q[i].s2;
while(top[s1]!=top[s2]){
//printf("working");
//printf("c:%d %d\n",top[s1],top[s2]);
if(d[top[s1]]<d[top[s2]])swap(s1,s2);
an=max(an,work(1,id[top[s1]],id[s1]));
s1=f[top[s1]];
}
if(d[s1]<d[s2])swap(s1,s2);
//printf("%d %d\n",s1,s2);
an=max(an,work(1,id[s2],id[s1]));
//printf("now:%d %d %d\n",q[i].wh,q[i].val,an);
ans[q[i].wh]=(an==q[i].val);
}
for(int i=1;i<=n;i++)printf("%d",ans[i]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具