BZOJ 2725 [Violet 6]故乡的梦

堆优dijkstra+线段树

膜:http://blog.csdn.net/popoqqq/article/details/47841783

为了表达清楚,记不删边时最短路为E1,删去某一条E1上的边之后的最短路为E2

显然E2一定是形如:S->沿着E1走到某一个在E1上点的S’->沿着不属于E1的一些边走到某一在E1上点的T’->沿着E1走到T

而且可以证明,上面提到的E2中不属于E1的那些边(组成一条路径)中,一定存在至少一条边,记它的两端点为u,v,使得E2上沿着S->u的路径是S->u在原图中的最短路,E2上沿着v->T的路径是v->T在原图中的最短路。

这个可以通过反证法证明,前提是原图为无向图。

然而其实这一题我并没有AC。。。不知道是因为复杂度退化了还是常数太大了,一直T。。。

#include<map>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
#define cmin(u,v) (u)>(v)?(u)=(v):0
#define mkp(a,b) (1ll*a*N+b)
#define reg register
using namespace std;
int in()
{
    register long long r = 0;
    register char c = getchar();
    while(c<'0'||c>'9')c = getchar();
    while(c>='0'&&c<='9')r = r*10+c-'0', c=getchar();
    return r;
}
char ss[100];
inline void out(long long x)
{
    if(x==0) {putchar(48); return;}
    char *s=ss;
    while(x) *(++s)=x%10, x/=10;
    while(s!=ss) putchar((*(s--))+48);
    putchar('\n');
}
map<long long,bool> PathEdge;
map<long long,int> PathId;
struct node
{
    int id;
    long long dis;
    node(){}
    node(int a, long long b):id(a),dis(b){}
}heap[N<<1];
struct Segment_tree
{
    int l, r;
    long long val, lazy;
}t[N*5];
struct edge{int from,next,to, val;}e[N<<1];
const long long INF = 1ll<<61;
long long dis[N], ds[N], dt[N], print[N];
int n, last[N], ecnt=1, fa[N], fs[N], ft[N], ll[N], rl[N], mapp[N], tcnt, ct[N], ctt, tot;
bool vis[N], PathPoint[N];
void addedge(int a, int b, int c)
{
    e[++ecnt]=(edge){a,last[a],b,c};
    last[a]=ecnt;
    PathId[mkp(a,b)]=ecnt;
}
void heap_add(node x)
{
    heap[++tot]=x;
    for(reg int i=tot,j=i>>1;j;i=j,j>>=1)
    {
        if(heap[j].dis>heap[i].dis)
            swap(heap[j],heap[i]);
        else break;
    }
}
void heap_pop()
{
    heap[1]=heap[tot--];
    for(reg int i=1,j=i<<1;j<=tot;i=j,j<<=1)
    {
        if(j<tot&&heap[j].dis>heap[j|1].dis)j|=1;
        if(heap[j].dis<heap[i].dis)
            swap(heap[j],heap[i]);
        else break; 
    }
}
void dijk(int s)
{
    memset(vis,0,sizeof(vis));
    memset(dis,0x7f,sizeof(dis));
    heap_add(node(s,dis[s]=0));
    while(tot)
    {
        int x=heap[1].id;
        heap_pop();
        if(vis[x])continue;
        vis[x]=1;
        for(reg int i = last[x]; i; i=e[i].next)
        {
            int y=e[i].to;
            if(vis[y] || dis[x]+e[i].val>=dis[y])continue;
            dis[y]=dis[x]+e[i].val;
            fa[y]=x;
            heap_add(node(y,dis[y]));
        }
    }
}
void dijk2(int s, int *fs, long long *ds)
{
    memset(vis,0,sizeof(vis));
    memset(ds,0x7f,sizeof(dis));
    heap_add(node(s,ds[s]=0));
    while(tot)
    {
        int x=heap[1].id;
        heap_pop();
        if(vis[x])continue;
        vis[x]=1;

        if(PathPoint[fa[x]] && (!PathPoint[x]))
            fs[x]=fa[x];
        else if(PathPoint[x])fs[x]=x;
        else fs[x]=fs[fa[x]];

        for(reg int i = last[x]; i; i=e[i].next)
        {
            int y=e[i].to;
            if(vis[y] || ds[x]+e[i].val>=ds[y])continue;
            ds[y]=ds[x]+e[i].val;
            fa[y]=x;
            heap_add(node(y,ds[y]));
        }
    }   
}
void pushdown(int x)
{
    cmin(t[x<<1].val,t[x].lazy);
    cmin(t[x<<1|1].val,t[x].lazy);
    cmin(t[x<<1].lazy,t[x].lazy);
    cmin(t[x<<1|1].lazy,t[x].lazy);
    t[x].lazy=INF;
}
void merge(int x)
{
    cmin(t[x].val,t[x<<1].val);
    cmin(t[x].val,t[x<<1|1].val);
}
void build(int x, int l, int r)
{
    t[x].l=l; t[x].r=r; t[x].val=INF; t[x].lazy=INF;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
}
void update(int x, int l, int r, long long v)
{
    pushdown(x);
    if(l<=t[x].l && t[x].r<=r)
    {
        cmin(t[x].val,v);
        cmin(t[x].lazy,v);
        return;
    }
    int mid=(t[x].l+t[x].r)>>1;
    if(l<=mid)update(x<<1,l,r,v);
    if(mid+1<=r)update(x<<1|1,l,r,v);
    merge(x);
}
void ask(int x)
{
    pushdown(x);
    if(t[x].l==t[x].r)
    {
        print[t[x].l]=t[x].val;
        return;
    }
    ask(x<<1);
    ask(x<<1|1);
}
int main()
{
    int m, s, t, Q;
    n=in();m=in();
    for(reg int i = 1, a, b, c; i <= m; i++)
    {
        a=in(); b=in(); c=in();
        addedge(a,b,c);
        addedge(b,a,c);
    }

    s=in(); t=in(); Q=in();

    dijk(s);

    PathPoint[s]=1;
    for(reg int pos = t; fa[pos]; pos=fa[pos])
    {
        ct[pos]=++ctt;
        PathPoint[pos]=1;
        PathEdge[mkp(pos,fa[pos])]=1;
        PathEdge[mkp(fa[pos],pos)]=1;
        ll[pos]=PathId[mkp(fa[pos],pos)]>>1;
        rl[fa[pos]]=PathId[mkp(fa[pos],pos)]>>1;
        mapp[ll[pos]]=++tcnt;
    }
    ct[s]=++ctt;

    fa[s]=0;dijk2(s,fs,ds);
    fa[t]=0;dijk2(t,ft,dt);
    build(1,1,ecnt>>1);

    for(reg int i = 2; i <= ecnt; i+=2)
    {
        int a=e[i].from, b=e[i].to, val=e[i].val;
        if(!PathEdge[mkp(a,b)])
        {
            if(mapp[ll[ft[b]]] && mapp[ll[ft[b]]]<=mapp[rl[fs[a]]])update(1,mapp[ll[ft[b]]],mapp[rl[fs[a]]],ds[a]+dt[b]+val);
            if(mapp[ll[ft[a]]] && mapp[ll[ft[a]]]<=mapp[rl[fs[b]]])update(1,mapp[ll[ft[a]]],mapp[rl[fs[b]]],ds[b]+dt[a]+val);
        }
    }
    if(dis[t]>=INF)
    {
        for(;Q--;)
            printf("Infinity\n");
        return 0;
    }
    memset(print,0x7f,sizeof(print));
    ask(1);
    for(;Q--;)
    {
        int a=in(), b=in();
        if(!PathEdge[mkp(a,b)])printf("%lld\n",dis[t]);
        else
        {
            if(ct[a]<ct[b])swap(a,b);
            long long ans = print[mapp[ll[ft[b]]]];
            if(ans==INF)printf("Infinity\n");
            else printf("%lld\n",ans);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值