��վ�ܷ�������

神题记录——归程

在学习了一波Kruskal重构树后,就来写了一下归程。

题目非常的长看起来非常恶心,仔细读了一下之后发现其实还好。

思路

首先我们需要求一波最短路,求出起点1到所有点的最短路。
然后就是构建一棵Kruskal 重构树
当然是按照海拔高度从大到小排序。

可以轻易发现,只要从v开始找找到了一个w[x]>p的点,求出x子树的所有点到1的dis最小值就行。

根据Kruskal重构树的性质,此时一个节点的子树的权值一定都大于w[x]
也就是一定不会有积水,找到此时最短的距离就行

所以我们需要在树链剖分dfs的时候直接维护一个子树最短的路径。
用倍增不断找这个x的点就行

代码

没有图的封装于是写的比较丑。。。。将就看看

#include <bits/stdc++.h>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
#define il inline
using namespace std;
const int M=4e5+110;
const int N=2e6+110;
const int inf=(1<<30);
int n,m,head[N],cnt,fa[2*N],deep[N],q,tot,vis[N],coc;
ll dis[N],w[N],last,ans[N];
int head2[N],s,k,father[N][30];
il ll read()
{
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct node
{
    int to,nt;
    ll w;
}edge[M*2],e2[M*2];
struct edg
{
    int u,v;
    ll w,h;
}e[N];
bool mmp(edg a,edg b)
{
    return a.h>b.h;
}
il void add(int x,int y)
{
    ++cnt;
    edge[cnt].nt=head[x];
    edge[cnt].to=y;
    head[x]=cnt;
    ++cnt;
    edge[cnt].nt=head[y];
    edge[cnt].to=x;
    head[y]=cnt;
}
il void add_edge(int x,int y,ll w)
{
    e2[++coc]=(node){y,head2[x],w};
    head2[x]=coc;
    e2[++coc]=(node){x,head2[y],w};
    head2[y]=coc;
}
il int findf(int x)
{
    if(x==fa[x])return x;
    else return fa[x]=findf(fa[x]);
}
il void Kruskal_build()
{
    tot=n;
    memset(w,0,sizeof(w));
    for(int i=1;i<=m;i++)
    {
        int fx=findf(e[i].u);
        int fy=findf(e[i].v);
        if(fx==fy)continue;
        tot++;
        add(tot,fx);
        add(tot,fy);
        fa[fx]=tot,fa[fy]=tot;
        w[tot]=e[i].h;

    }
}
il void dfs(int x,int fa1,int d)
{
    deep[x]=d;
    father[x][0]=fa1;
    for(int i=1;(1<<i)<deep[x];i++)
        father[x][i]=father[father[x][i-1]][i-1];
    for(int i=head[x];i;i=edge[i].nt)
    {
        int v=edge[i].to;
        if(v==fa1)continue;
        dfs(v,x,d+1);
        ans[x]=min(ans[x],ans[v]);
    }
}
il void Dijkstra()
{
    for(int i=1;i<=n;i++)dis[i]=(1<<30),vis[i] = 0;
    priority_queue<pair<int,int> ,vector<pair<int,int > >,greater<pair<int,int> > >q;
    q.push(make_pair(0,1));
    dis[1]=0;;
    while(!q.empty())
    {
        int u=q.top().second,w=q.top().first;
        q.pop();
        if(vis[u])continue;vis[u]=1;
        for(int i=head2[u];i;i=e2[i].nt)
        {
            int v=e2[i].to;
            if(dis[v]>dis[u]+e2[i].w)
            {
                dis[v]=dis[u]+e2[i].w;
                q.push(make_pair(dis[v],v));
            }
        }
    }

}
ll query(int x,int p)
{
    for(int i=20;i>=0;i--)
    {
        if((1<<i)<=deep[x]&&w[father[x][i]]>p)
            x=father[x][i];
    }
    return ans[x];
}
int Case;
int main()
{
    Case=read();
    while(Case--)
    {
        n=read();m=read();
        cnt=0,tot=0;coc=0;
        memset(edge,0,sizeof(edge));
        memset(head,0,sizeof(head));
        memset(head2,0,sizeof(head2));
        memset(e2,0,sizeof(e2));
        memset(father, 0, sizeof(father));
        for(int i=1;i<=n;i++)
            fa[i]=i,fa[i+n]=i+n;
        for(int i=1;i<=m;i++)
            e[i].u=read(),e[i].v=read(),e[i].w=read(),e[i].h=read(),add_edge(e[i].u,e[i].v,e[i].w);
        sort(e+1,e+1+m,mmp);
        Dijkstra();
        Kruskal_build();
        int rt=findf(1);
        for(int i=1;i<=n;i++)
            ans[i]=dis[i],ans[i+n]=inf;
        dfs(rt,0,rt);
        last=0;
        q=read();k=read();s=read();
        for(int i=1;i<=q;i++)
        {
            int v0,v;
            ll p0,p;
            v0=read();p0=read();
            v=(v0+k*last-1)%n+1;
            p=(p0+k*last)%(s+1);
            last=query(v,p);
            printf("%lld\n",last);
        }

    }

    return 0;
}