[NOI2018]归程
题目
思路
做过peaks的话这道题简直就水的不行(\(peaks\)弱化版?)
先从1向所有点跑一次最短路求出\(dis\)(此题略卡\(spfa\)),按照海拔从大到小做出\(kruskal\)重构树,\(dfs\)一遍预处理出每个点对应的子树的最小\(dis\),对于每个海拔限制,倍增找到深度最小的满足条件的节点,则\(ans=mindis\)
两道题的不同点:peaks还要求第k小,要用主席树;这道题求最小值,可以直接预处理(当然还要跑最短路)
Code
(受\(peaks\)影响,蠢的一批的用\(ST+dfs\)序求的子树中的最小\(dis\),这个东西显然可以\(O(1)\)递推的。。。懒得改了)
#include<bits/stdc++.h>
#define N 400005
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
using namespace std;
int T,n,m,ndsum,fa[N],val[N];
int dis[N],l[N],r[N],rev[N],cc;
int f[N][20],dep[N],st[N][20],lg[N];
bool vis[N];
struct Edge
{
int next,to,dis;
}edge[N<<2];int head[N],cnt=1;
struct E {int u,v,l,a;} e[N];
void add_edge(int from,int to,int dis)
{
edge[++cnt].next=head[from];
edge[cnt].to=to;
edge[cnt].dis=dis;
head[from]=cnt;
}
template <class T>
void read(T &x)
{
char c;int sign=1;
while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
}
void init()
{
memset(dep,0,sizeof(dep));
memset(head,0,sizeof(head));
cnt=1;cc=0;
}
bool cmp(E a,E b) {return a.a>b.a;}
int find(int x) {return x==fa[x] ? x : fa[x]=find(fa[x]);}
void dijkstra(int s)
{
memset(dis,100,sizeof(dis));
memset(vis,0,sizeof(vis));
priority_queue< pair<int,int> > q;
dis[s]=0; q.push(make_pair(-dis[s],s));
while(!q.empty())
{
int u=q.top().second; q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].dis)
{
dis[v]=dis[u]+edge[i].dis;
if(!vis[v]) q.push(make_pair(-dis[v],v));
}
}
}
}
void kruskal()
{
ndsum=n;
for(int i=1;i<=n*2;++i) fa[i]=i;
sort(e+1,e+m+1,cmp);
int tot=0;
for(int i=1;i<=m;++i)
{
int fx=find(e[i].u),fy=find(e[i].v);
if(fx==fy) continue;
val[++ndsum]=e[i].a;
add_edge(ndsum,fx,0);
add_edge(ndsum,fy,0);
fa[fx]=fa[fy]=ndsum;
}
}
void dfs(int rt)
{
l[rt]=n+1,r[rt]=0;
if(rt<=n)
{
l[rt]=r[rt]=++cc;
rev[cc]=rt;
return;
}
for(int i=head[rt];i;i=edge[i].next)
{
int v=edge[i].to;
dep[v]=dep[rt]+1;
f[v][0]=rt;
for(int j=1;j<20;++j) f[v][j]=f[f[v][j-1]][j-1];
dfs(v);
l[rt]=Min(l[rt],l[v]);
r[rt]=Max(r[rt],r[v]);
}
}
int lca(int start,int maxx)
{
for(int i=19;i>=0;--i)
if(f[start][i]&&val[f[start][i]]>maxx)
start=f[start][i];
return start;
}
void ST()
{
memset(st,125,sizeof(st));
for(int i=n;i>=1;--i)
{
st[i][0]=dis[rev[i]];
for(int j=1;i+(1<<j)-1<=n;++j)
{
st[i][j]=Min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
}
}
int ask(int l,int r)
{
int tp=lg[r-l+1];
return Min(st[l][tp],st[r-(1<<tp)+1][tp]);
}
int main()
{
read(T);
lg[0]=-1;
for(int i=1;i<N;++i) lg[i]=lg[i>>1]+1;
while(T--)
{
init();
read(n);read(m);
for(int i=1;i<=m;++i)
{
read(e[i].u);read(e[i].v);
read(e[i].l);read(e[i].a);
add_edge(e[i].u,e[i].v,e[i].l);
add_edge(e[i].v,e[i].u,e[i].l);
}
dijkstra(1);
memset(head,0,sizeof(head));
cnt=1;
kruskal();
dfs(ndsum);
ST();
int q,k,s,lasans=0;
read(q);read(k);read(s);
while(q--)
{
int v,p;
read(v);read(p);
v=((long long)v+k*lasans-1)%n+1;
p=((long long)p+k*lasans)%(s+1);
int lc=lca(v,p);
lasans=ask(l[lc],r[lc]);
printf("%d\n",lasans);
}
}
return 0;
}