「NOI2018」归程

题链:https://loj.ac/problem/2718

 

由于有无积水对行走没有影响,所以先预处理出每个点到1号点的路径

问题就变成了求一个联通块中最小值

 

两种方法:

1、用可持久化并查集维护,在根节点记录最小值

2、用kruskal重构树维护,用ST表维护最小值

 

方法1代码:

#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;

const int N=2e6+5,M=2e7+5;;
struct A{ int fa,r,v; }c[M];
int n,m,r[N],ls[M],rs[M],rt[N],ans;
int cnt,to[N],nxt[N],he[N],dis[N],w[N],rtw[N];
bool fl[N];

struct B{int id,x;};
bool operator >(B i,B j){return i.x>j.x; }
priority_queue<B,vector<B>,greater<B> >q;

struct C{int u,v,h; }e[N];
bool cmp(C i,C j){return i.h>j.h;}

void write(int x)
{
    if(x/10) write(x/10);
    putchar(x%10+48);
}

inline int read()
{
    int ret=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')
        ch=getchar();
    while(ch>='0'&&ch<='9')
    {
        ret=(ret<<1)+(ret<<3)+ch-'0';
        ch=getchar();
    }
    return ret;
}

void build(int &p,int l,int r)
{
    p=++cnt;
    if(l==r)
    {
        c[p]=(A){l,0,dis[l]};
        return;
    }
    int mid=l+r>>1;
    build(ls[p],l,mid);
    build(rs[p],mid+1,r);
}

A get(int p,int l,int r,int x)
{
    if(l==r) 
        return c[p];
    int mid=l+r>>1;
    if(x<=mid) 
        return get(ls[p],l,mid,x);
    else 
        return get(rs[p],mid+1,r,x);
}

void update(int p1,int &p2,int l,int r,int x,A y)
{
    ls[++cnt]=ls[p1];
    rs[cnt]=rs[p1];
    p2=cnt;
    if(l==r)
    {
        c[p2]=y;
        return;
    }
    int mid=l+r>>1;
    if(x<=mid) 
        update(ls[p1],ls[p2],l,mid,x,y);
    else
        update(rs[p1],rs[p2],mid+1,r,x,y);
}

A find(int root,int u)
{
    A x=get(root,1,n,u);
    return u==x.fa?x:find(root,x.fa);
}

inline void add(int u,int v,int k)
{
    to[++cnt]=v;
    nxt[cnt]=he[u];
    w[cnt]=k;
    he[u]=cnt;
}

int findr(int x)
{
    int l=1,r=n-1,ans=0;
    while(l<=r)
    {
        int mid=l+r>>1;
        if(rtw[mid]>=x) 
        {
            ans=mid;
            l=mid+1;
        }else
            r=mid-1;
    }	
    return ans;
}
int main()
{
    freopen("return.in","r",stdin);  //这道题一定要文件输入输出,否则TLE
    freopen("return.out","w",stdout);
    int T=read();
    while(T--)
    {
        n=read(),m=read();
        for(int i=1;i<=n;i++)
            he[i]=0;
        cnt=0;
        for(int i=1;i<=m;i++)
        {
            e[i].u=read(),e[i].v=read();
            int k=read();
            e[i].h=read();
            add(e[i].u,e[i].v,k);
            add(e[i].v,e[i].u,k);
        }
        for(int i=1;i<=n;i++)
        {
            dis[i]=1e9;
            fl[i]=0;
        }
        while(!q.empty()) q.pop();
        q.push((B){1,dis[1]=0});
        for(int i=1;i<=n;i++)
        {
            while(fl[q.top().id]) q.pop();
            int u=q.top().id;
            fl[u]=1;
            for(int E=he[u];E;E=nxt[E])
            {
                int v=to[E];
                if(!fl[v]&&dis[v]>dis[u]+w[E])
                    q.push((B){v,dis[v]=dis[u]+w[E]});
            }
        }
        sort(e+1,e+m+1,cmp);
        cnt=0;
        build(rt[0],1,n);
        int tot=0;
        for(int i=1;i<=m;i++)
        {
            A u=find(rt[tot],e[i].u),v=find(rt[tot],e[i].v);
            if(u.fa!=v.fa)
            {
                ++tot;
                rt[tot]=rt[tot-1];
                rtw[tot]=e[i].h;
                if(u.r>v.r)
                {
                    update(rt[tot-1],rt[tot],1,n,v.fa,(A){u.fa,v.r,v.v});
                    update(rt[tot],rt[tot],1,n,u.fa,(A){u.fa,u.r,min(u.v,v.v)});
                }
                else 
                    if(u.r==v.r)
                    {
                        update(rt[tot-1],rt[tot],1,n,u.fa,(A){v.fa,u.r,u.v});
                        update(rt[tot],rt[tot],1,n,v.fa,(A){v.fa,v.r+1,min(u.v,v.v)});
                    }
                else
                {
                    update(rt[tot-1],rt[tot],1,n,u.fa,(A){v.fa,u.r,u.v}); 
                    update(rt[tot],rt[tot],1,n,v.fa,(A){v.fa,v.r,min(u.v,v.v)});
                }
                if(tot==n-1) break;
            }
        }
        int q=read(),K=read(),S=read();
        ans=0;
        while(q--)
        {
            int v=(read()+K*ans-1)%n+1,p=(read()+K*ans)%(S+1);
            int edi=findr(p+1);
            write(ans=find(rt[edi],v).v),puts("");
        }
        for(int i=1;i<=cnt;i++)
        {
            ls[i]=0;
            rs[i]=0;
        }
    }
    return 0;
}

 

方法2:

#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;

const int N=1e6+5;
int n,m,ans,tot,dfn,in[N],out[N],dy[N];
int fa[N],fi[N][20],fw[N][20],son[N][2];
int cnt,to[N],nxt[N],he[N],dis[N],w[N];
int lg[N],f[N][20];
bool fl[N];

struct B{int id,x;};
bool operator >(B i,B j){return i.x>j.x; }
priority_queue<B,vector<B>,greater<B> >q;

struct C{int u,v,h; }e[N];
bool cmp(C i,C j){return i.h>j.h;}

void write(int x)
{
    if(x/10) write(x/10);
    putchar(x%10+48);
}

inline int read()
{
    int ret=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')
        ch=getchar();
    while(ch>='0'&&ch<='9')
    {
        ret=(ret<<1)+(ret<<3)+ch-'0';
        ch=getchar();
    }
    return ret;
}

inline void add(int u,int v,int k)
{
    to[++cnt]=v;
    nxt[cnt]=he[u];
    w[cnt]=k;
    he[u]=cnt;
}

int find(int x)
{
    return x==fa[x]?x:fa[x]=find(fa[x]);
}

void dfs(int u)
{
    if(u<=n) 
    {
        dfn++;
        in[u]=out[u]=dfn;
        dy[dfn]=u;
        return;
    }
    dfs(son[u][0]);
    dfs(son[u][1]);
    in[u]=in[son[u][0]];
    out[u]=out[son[u][1]];
}

inline int get(int l,int r)
{
    int k=lg[r-l+1];
    return min(f[l][k],f[r-(1<<k)+1][k]);
}

int main()
{
    freopen("return.in","r",stdin);
    freopen("return.out","w",stdout);
    int T=read();
    lg[0]=-1;
    for(int i=1;i<=1000000;i++)
        lg[i]=lg[i>>1]+1;
    while(T--)
    {
        n=read(),m=read();
        for(int i=1;i<=n;i++)
            he[i]=0;
        cnt=0;
        for(int i=1;i<=m;i++)
        {
            e[i].u=read(),e[i].v=read();
            int k=read();
            e[i].h=read();
            add(e[i].u,e[i].v,k);
            add(e[i].v,e[i].u,k);
        }
        for(int i=1;i<=n;i++)
        {
            dis[i]=1e9;
            fl[i]=0;
        }
        while(!q.empty()) q.pop();
        q.push((B){1,dis[1]=0});
        for(int i=1;i<=n;i++)
        {
            while(fl[q.top().id]) q.pop();
            int u=q.top().id;
            fl[u]=1;
            for(int E=he[u];E;E=nxt[E])
            {
                int v=to[E];
                if(!fl[v]&&dis[v]>dis[u]+w[E])
                    q.push((B){v,dis[v]=dis[u]+w[E]});
            }
        }
        sort(e+1,e+m+1,cmp);
        for(int i=1;i<=n+n-1;i++)
            fa[i]=i;
        tot=n; 
        for(int i=1;i<=m;i++)
        {
            int u=find(e[i].u),v=find(e[i].v);
            if(u!=v) 
            {
                tot++;
                fa[u]=tot;
                fa[v]=tot;
                fi[u][0]=tot;
                fw[u][0]=e[i].h;
                fi[v][0]=tot;
                fw[v][0]=e[i].h;
                fw[tot][0]=e[i].h; 
                son[tot][0]=u;
                son[tot][1]=v;
                if(tot==n+n-1) break;
            }
        }
        fi[tot][0]=tot;
        for(int j=1;j<=lg[tot];j++)
            for(int i=1;i<=tot;i++)
            {
                fi[i][j]=fi[fi[i][j-1]][j-1];
                fw[i][j]=min(fw[i][j-1],fw[fi[i][j-1]][j-1]);
            }
        dfn=0; 	
        dfs(tot);
        for(int i=1;i<=n;i++)
            f[i][0]=dis[dy[i]];
        for(int j=1;j<=lg[n];j++)
            for(int i=1;i<=n-(1<<j)+1;i++)
                f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
        int q=read(),K=read(),S=read();
        ans=0;
        while(q--)
        {
            int v=(read()+K*ans-1)%n+1,p=(read()+K*ans)%(S+1);
            for(int i=lg[tot];i>=0;i--)
                if(fw[v][i]>=p+1)
                    v=fi[v][i];
            ans=get(in[v],out[v]);
            write(ans),puts("");
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值