[NOI2018] 归程
P4768 [NOI2018] 归程
题目描述
本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定。
魔力之都可以抽象成一个
作为季风气候的代表城市,魔力之都时常有雨水相伴,因此道路积水总是不可避免的。由于整个城市的排水系统连通,因此有积水的边一定是海拔相对最低的一些边。我们用水位线来描述降雨的程度,它的意义是:所有海拔不超过水位线的边都是有积水的。
Yazid 是一名来自魔力之都的 OIer,刚参加完 ION2018 的他将踏上归程,回到他温暖的家。Yazid 的家恰好在魔力之都的
每一天,Yazid 在出发点都拥有一辆车。这辆车由于一些故障不能经过有积水的边。Yazid 可以在任意节点下车,这样接下来他就可以步行经过有积水的边。但车会被留在他下车的节点并不会再被使用。
需要特殊说明的是,第二天车会被重置,这意味着:
- 车会在新的出发点被准备好。
- Yazid 不能利用之前在某处停放的车。
Yazid 非常讨厌在雨天步行,因此他希望在完成回家这一目标的同时,最小化他步行经过的边的总长度。请你帮助 Yazid 进行计算。
数据范围与约定
所有测试点均保证
-
, , , , 。 -
对于所有边:
, 。 -
任意两点之间都直接或间接通过边相连。
-
强制在线
Solution:
kruskal 重构树魅力时刻。
其实如果写过 P4197 Peaks 的话那么这题几乎是纯送的。
先分析题意:
我们先求出原图上以1为起点的单源最短路,然后题目要求我们在一个联通图上求出从一个点
实现:
我们发现
至于如何查询
Code:
#include<bits/stdc++.h> const int N=4e5+5; const int inf=1e9; const int lg=20; using namespace std; int n,m,days,ans; vector<tuple<int,int> > E[N]; vector<int> e[N<<1]; int val[N],dis[N]; struct Edge{ int x,y,w; bool operator <(const Edge &e)const{ return w>e.w; } }q[N]; struct Kruskal{ int fa[N],tot; int find(int x){return fa[x]= fa[x]==x ? fa[x] : find(fa[x]);} void add(int x,int y){e[x].emplace_back(y);} void build() { tot=n; for(int u=1;u<=n;u++)fa[u]=u; for(int i=1;i<=m;i++) { int x=q[i].x,y=q[i].y,w=q[i].w; int u=find(x),v=find(y); if(u!=v) { val[++tot]=w; add(tot,v);add(tot,u); //cout<<"add:"<<tot<<" : "<<u<<" "<<v<<"="<<w<<"\n"; fa[tot]=fa[u]=fa[v]=tot; } } } }K; struct Dijkstra{ struct Node{ int x,val; bool operator<(const Node &n)const{ return n.val<val; } }; priority_queue<Node> Q; int vis[N]; void init() { for(int i=1;i<=n;i++)dis[i]=inf,vis[i]=0; } void dijksta(int s) { init(); dis[s]=0;Q.push({s,dis[s]}); while(!Q.empty()) { int x=Q.top().x;Q.pop(); if(vis[x])continue; vis[x]=1; for(auto [y,w] : E[x]) { if(dis[y]>dis[x]+w) { dis[y]=dis[x]+w; Q.push({y,dis[y]}); } } } } }D; struct Graph{ int dfn[N<<1]; int f[N<<1][lg+5]; int st[N<<1],ed[N<<1]; void dfs(int x,int fa) { st[x]=++dfn[0]; f[x][0]=fa; for(int j=1;j<=lg;j++)f[x][j]=f[f[x][j-1]][j-1]; for(auto y : e[x]) { if(y==fa)continue; dfs(y,x); } ed[x]=dfn[0]; } int find(int x,int k) { for(int j=lg;j>=0;j--)if(val[f[x][j]]>k)x=f[x][j]; return x; } }G; struct ST{ int LG[N<<1]; int st[N<<1][lg+5]; int R; void init() { R=(n<<1)-1; for(int i=2;i<=R;i++)LG[i]=LG[i>>1]+1; for(int i=1;i<=R;i++)st[i][0]=inf; for(int i=1;i<=n;i++)st[G.st[i]][0]=dis[i]; } void build() { init(); //cout<<"R:"<<R<<"\n"; //for(int i=1;i<=R;i++)cout<<st[i][0]<<(i==R ? "\n" : " "); for(int j=1;j<=lg;j++)for(int i=1;i<=R;i++) { int tmp=min(i+(1<<j-1),R); st[i][j]=min(st[i][j-1],st[tmp][j-1]); } } int query(int l,int r) { int k=LG[r-l+1]; return min(st[l][k],st[r-(1<<k)+1][k]); } }S; struct Change{ int k,s; int chage_v(int x){return (x+k*ans-1)%n+1;} int chage_p(int x){return (x+k*ans)%(s+1);} }C; void Clear() { int R=(n<<1)-1;G.dfn[0]=0; for(int i=1;i<=n;i++)E[i].clear(); for(int i=1;i<=R;i++)e[i].clear(),val[i]; } void work() { cin>>n>>m; ans=0; for(int i=1,x,y,w,h;i<=m;i++) { scanf("%d%d%d%d",&x,&y,&w,&h); E[x].emplace_back(y,w); E[y].emplace_back(x,w); q[i]={x,y,h}; } sort(q+1,q+1+m); D.dijksta(1); K.build(); G.dfs(K.tot,0); S.build(); cin>>days>>C.k>>C.s; for(int i=1,v,p;i<=days;i++) { scanf("%d%d",&v,&p); v=C.chage_v(v);p=C.chage_p(p); //cout<<"v p : "<<v<<" "<<p<<"\n"; v=G.find(v,p); ans=S.query(G.st[v],G.ed[v]); //cout<<v<<"="<<G.st[v]<<" "<<G.ed[v]<<"\n"; printf("%d\n",ans); } //cout<<"END\n"; Clear(); } int main() { //freopen("P4768_2.in","r",stdin);freopen("P4768.out","w",stdout); int T; cin>>T; while(T--) work(); return 0; }