loj 2718. 「NOI2018」归程

9 篇文章 0 订阅
5 篇文章 0 订阅

题意:

给一个图,每次询问从某个点出发,先坐车经过一些权值大于 p p <script type="math/tex" id="MathJax-Element-31">p</script>的边,然后下车走到1,问走的最短距离,强制在线。

题解:

蒟蒻选手没有去noi,听说这是道签到题,看下能否成功签到。
因为知道是kruskal重构树所以就成功签到了啦啦啦。
建出最大kruskal重构树,因为重构树上的点的点权是由根至叶子递增的,倍增找到那个点,其子树就是起始点出发能到的点,dij预处理即可。
多组数据忘了初始化幸好不在现场
code:

#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const LL inf=1LL<<60;
struct Node{
    LL x,y,c,a,next;
}e[400010],a[800010];LL len=0,last[200010];
LL Fa[400010],c[400010],dep[400010],fa[400010][22],son[400010][2];
LL dis[200010],root,p,v,Min[400010];
bool vis[200010];
struct node{
    LL x,d;
    node() {}
    node(LL a,LL b) {x=a;d=b;}
};
bool operator < (node a,node b) {return a.d>b.d;}
LL n,m,Q,K,S;
LL findfa(LL x) {return Fa[x]==x?x:Fa[x]=findfa(Fa[x]);}
void ins(LL x,LL y,LL c)
{
    a[++len].y=y;a[len].c=c;
    a[len].next=last[x];last[x]=len;
}
priority_queue<node> q;
void dij()
{
    memset(vis,false,sizeof(vis));
    for(LL i=1;i<=n;i++) dis[i]=inf;dis[1]=0;
    q.push(node(1,0));
    while(!q.empty())
    {
        node t=q.top();q.pop();LL x=t.x;
        if(vis[x]) continue;vis[x]=true;
        for(LL i=last[x];i;i=a[i].next)
        {
            LL y=a[i].y;
            if(dis[y]>dis[x]+a[i].c) dis[y]=dis[x]+a[i].c,q.push(node(y,dis[y]));
        }
    }
}
bool cmp(Node a,Node b) {return a.a>b.a;}
void dfs(LL x,LL f)
{
    dep[x]=dep[f]+1;fa[x][0]=f;
    for(LL i=1;(1<<i)<=dep[x];i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    if(son[x][0])
    {
        dfs(son[x][0],x);dfs(son[x][1],x);
        Min[x]=min(Min[son[x][0]],Min[son[x][1]]);
    }
    else Min[x]=dis[x];
}
LL ans=0;
void solve(LL x)
{
    for(LL i=20;i>=0;i--)
        if((1<<i)<=dep[x]&&c[fa[x][i]]>p) x=fa[x][i];
    ans=Min[x];printf("%lld\n",Min[x]);
}
int main()
{
    //freopen("return.in","r",stdin);
    //freopen("return.out","w",stdout);
    LL T;scanf("%lld",&T);
    while(T--)
    {
        scanf("%lld %lld",&n,&m);root=n;
        for(LL i=1;i<=2*n;i++) Fa[i]=i;
        len=0;memset(last,0,sizeof(last));
        memset(son,0,sizeof(son));
        memset(fa,0,sizeof(fa));
        for(LL i=1;i<=m;i++)
        {
            LL x,y,l,k;scanf("%lld %lld %lld %lld",&x,&y,&l,&k);
            e[i].x=x;e[i].y=y;e[i].c=l;e[i].a=k;
            ins(x,y,l);ins(y,x,l);
        }
        dij();
        sort(e+1,e+m+1,cmp);
        for(LL i=1;i<=m;i++)
        {
            LL tx=findfa(e[i].x),ty=findfa(e[i].y);
            if(tx==ty) continue;
            Fa[tx]=Fa[ty]=++root;c[root]=e[i].a;
            son[root][0]=tx;son[root][1]=ty;
        }
        dep[0]=-1;dfs(root,0);ans=0;
        scanf("%lld %lld %lld",&Q,&K,&S);
        while(Q--)
        {
            scanf("%lld %lld",&v,&p);
            v=(v+K*ans-1)%n+1;p=(p+K*ans)%(S+1);
            solve(v);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值