NOIP2016&洛谷P1600:天天爱跑步
2021/11/1 23:10:35
本文主要是介绍NOIP2016&洛谷P1600:天天爱跑步,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 解析
- sol1:树剖+map
- sol2:树剖+离线
- sol3:dfs维护树状数组+差分
解析
个人认为本题比同年的逛公园可做许多
本题的一个关键是:把慢跑者 ( u , v ) (u,v) (u,v)转化为上升路径上满足 d e p x + t x = d e p u dep_x+t_x=dep_u depx+tx=depu的结点和下降路径上满足 − d e p + x + t x = d e p u − 2 ∗ d e p l c a -dep+x+t_x=dep_u-2*dep_{lca} −dep+x+tx=depu−2∗deplca的结点x的答案均加一
这个感觉不是很难想,由于每秒跑一步的特性,很容易想到这个和深度的联系
然后就是怎么维护上面那个玩意了
sol1:树剖+map
时间复杂度:O(nlogn^3)
得分:95pts
这是我一开始想到的解法
第一交95pts也可以接受了吧
极其好写
就是对线段树每个结点开个map,做一个标记永久化,然后询问的时候沿途把标记捡起来就行了
修改过程中只会在最终打标记处改变map
一开始我觉得这个改变次数是O(1)的,但是这个是**假的!!**在最差情况下会退化成Ologn个(比如修改[1,n-1]的区间时)
这样复杂度就升到了nlogn^3,无法通过了
T掉3e5的数据也是合情合理
由于树剖自带的小常数+氧气加持+上面那个第三个log完全跑不满(现在终于可以默认有O2了!),得到95分也算合理
(然而关掉氧气由于垃圾的map常数就只有25pts)
sol2:树剖+离线
时间复杂度:nlogn^2
得分:100pts
稍微思考一下就可以想到真的做法
注意到所有的操作和询问都是针对一个特定的值,把他们离线下来从大到小处理即可
询问的时候用到一个先减后加从而求出变化量
这个就跑的飞快了
也不再耗氧
### 代码
#include<bits/stdc++.h> using namespace std; #define ll long long #define il inline #define debug(a,b) fprintf(stderr,a,b) const int N=3e5+100; const double eps=1e-9; inline ll read() { ll x=0,f=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) { x=(x<<1)+(x<<3)+c-'0'; c=getchar(); } return x*f; } int n,m; struct node { int to,nxt; } p[N<<1]; int fi[N],cnt; inline void addline(int x,int y) { p[++cnt]=(node) { y,fi[x] }; fi[x]=cnt; return; } int fa[N],siz[N],dep[N],hson[N],top[N],dfn[N],pos[N],tim; void dfs1(int x,int f) { fa[x]=f;dep[x]=dep[f]+1; siz[x]=1; for(int i=fi[x]; ~i; i=p[i].nxt) { int to=p[i].to; if(to==f) continue; dfs1(to,x); siz[x]+=siz[to]; if(siz[to]>siz[hson[x]]) hson[x]=to; } return; } void dfs2(int x,int tp) { top[x]=tp; dfn[++tim]=x;pos[x]=tim; if(hson[x]) dfs2(hson[x],tp); for(int i=fi[x]; ~i; i=p[i].nxt) { int to=p[i].to; if(to==hson[x]||to==fa[x]) continue; dfs2(to,to); } return; } inline int Lca(int x,int y){ while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); x=fa[top[x]]; } if(dep[x]<dep[y]) swap(x,y); return y; } #define mid ((l+r)>>1) #define ls (k<<1) #define rs (k<<1|1) int ans[N]; struct tree{ int val[N<<2]; int ask(int k,int l,int r,int x){ int res=val[k]; if(l==r) return res; if(x<=mid) return ask(ls,l,mid,x)+res; else return ask(rs,mid+1,r,x)+res; } void change(int k,int l,int r,int x,int y){ if(x>y) return; //printf("k=%d (%d %d) x=%d y=%d v=%d\n",k,l,r,x,y,v); if(x<=l&&r<=y){ val[k]++; return; } if(x<=mid) change(ls,l,mid,x,y); if(y>mid) change(rs,mid+1,r,x,y); return; } inline void Add(int x,int anc,int flag){ while(top[x]!=top[anc]){ change(1,1,n,pos[top[x]],pos[x]); x=fa[top[x]]; } change(1,1,n,pos[anc]+flag,pos[x]); return; } }t[2]; int tt[N]; int tot1,tot2; struct ope{ int x,anc,val,op; bool operator < (const ope u)const{return val<u.val;} }o[N<<1]; struct query{ int x,val,op; bool operator < (const query u)const{return val<u.val;} }q[N<<1]; int main() { #ifndef ONLINE_JUDGE //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); #endif memset(fi,-1,sizeof(fi));cnt=-1; n=read(); m=read(); for(int i=1; i<n; i++) { int x=read(),y=read(); addline(x,y); addline(y,x); } dfs1(1,0); dfs2(1,1); for(int i=1;i<=n;i++){ tt[i]=read(); q[++tot1]=(query){i,tt[i]+dep[i],0}; q[++tot1]=(query){i,tt[i]-dep[i],1}; } //for(int i=1;i<=n;i++) printf("x=%d fa=%d dep=%d t=%d pos=%d v1=%d v2=%d\n",i,fa[i],dep[i],t[i],pos[i],t[i]+dep[i],t[i]-dep[i]); for(int i=1;i<=m;i++){ int x=read(),y=read(); int lca=Lca(x,y); o[++tot2]=(ope){x,lca,dep[x],0}; o[++tot2]=(ope){y,lca,dep[x]-2*dep[lca],1}; //t1.Add(x,lca,dep[x],1); //t2.Add(y,lca,dep[x]-2*dep[lca],0); //printf("x=%d y=%d lca=%d v1=%d v2=%d\n",x,y,lca,dep[x],dep[x]-2*dep[lca]); } sort(q+1,q+1+tot1);sort(o+1,o+1+tot2); int pl1=1,pl2=1; for(int tim=-2*n;tim<=2*n;tim++){ for(int i=pl1;i<=tot1&&q[i].val==tim;i++){ int now=q[i].x; ans[now]-=t[q[i].op].ask(1,1,n,pos[now]); } while(pl2<=tot2&&o[pl2].val==tim){ t[o[pl2].op].Add(o[pl2].x,o[pl2].anc,o[pl2].op); ++pl2; } while(pl1<=tot1&&q[pl1].val==tim){ int now=q[pl1].x; ans[now]+=t[q[pl1].op].ask(1,1,n,pos[now]); ++pl1; } } for(int i=1;i<=n;i++){ printf("%d ",ans[i]); } return 0; } /* 6 1 2 3 1 2 1 4 4 5 4 6 0 2 5 1 2 3 1 5 */
sol3:dfs维护树状数组+差分
时间复杂度:nlogn
得分:100pts
写完看的题解的思路
这个东西是真的好强大
有点四两拨千斤的感觉
以后可以多往这方面想一想
就是把我上面维护的东西离线到各个结点上
维护树状数组并利用前后差值求出答案
(应该)跑的飞快
说是应该是因为我并没有再写一遍
这篇关于NOIP2016&洛谷P1600:天天爱跑步的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南