洛谷P1710 地铁涨价 图论

其实是个傻逼题但是我太傻逼了然后就错了无数遍总算A了 觉得不写个题解真是亏了

其实是 之前想了个超时想法 然后还自以为很对?后来看了题解发现还是比较妙的哦 于是就想着那还是发个题解记录下趴quq

传送门 ...惊觉之前好几道题解都没放链接了,,,ummm,,,有时间再补趴QAQ

正解:没什么tag就图论常见套路?

解题报告:

首先总结下这类删边题目的常见套路?就是 离线做,倒着加边(之前翻讨论说好像在线也能A掉?有点强哦qwq想着过段时间去看下趴qwq

然后这个题目,我先港下我最开始想到的傻逼超时想法趴

就是,每次加边我就判断能否改变,如果能改变就改变啊,然后就f++啊,如果之前改过f了后面又改那肯定前面的就不作数了(因为我是倒着加边嘛,前面其实相当于是后来的,就是说 如果你开始就不满了,后来满不满就都一样了,反正不会对答案造成贡献了咯

然后狂写一通

0分 ummm是因为犯了些傻逼错误后面会港的

发现傻逼错误之后又改了一下,最后是T了俩点,80

放下代码趴纪念下我逝去的仨小时...

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rp(i,x,y) for(register ll i=x;i<=y;++i)
#define my(i,x,y) for(register ll i=x;i>=y;--i)
#define P pair<ll,ll>
#define mp make_pair

ll n,m,q,head[1000000+10],a[1000000+10],b[1000000+10],r[1000000+10],tot,dis[1000000+10],f[1000000+10],ans,QAQ[1000000+10];
bool lq[1000000+10],vis[1000000+10];
struct ed{ll to,next;}edge[4000010];
priority_queue< P,vector< P >,greater< P > >Q;

inline ll read()
{
    char ch=getchar();ll x=0;bool y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=getchar();
    if(ch=='-')ch=getchar(),y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
    return y?x:-x;
}
inline void add(ll x,ll y){edge[++tot].to=x;edge[tot].next=head[y];head[y]=tot;}
inline void dij()
{
    memset(dis,127/3,sizeof(dis));Q.push(mp(0,1));vis[1]=1;dis[1]=0;
    while(!Q.empty())
    {
        ll t=Q.top().second;Q.pop();
        for(ll i=head[t];i!=0;i=edge[i].next)
            if(dis[edge[i].to]>dis[t]+1){dis[edge[i].to]=dis[t]+1;if(!vis[edge[i].to])Q.push(mp(dis[t]+1,edge[i].to)),vis[edge[i].to]=1;}
    }
}
inline void update(ll u,ll tim)
{
    memset(vis,0,sizeof(vis));Q.push(mp(dis[u],u));vis[u]=1;if(QAQ[u]!=0)f[QAQ[u]]--;QAQ[u]=tim;
    while(!Q.empty())
    {
        ll t=Q.top().second;Q.pop();
        for(ll i=head[t];i!=0;i=edge[i].next)
            if(dis[edge[i].to]>dis[t]+1)
            {
                ans++;if(QAQ[edge[i].to]!=0)f[QAQ[edge[i].to]]--;QAQ[edge[i].to]=tim;dis[edge[i].to]=dis[t]+1;
                if(!vis[edge[i].to])Q.push(mp(dis[t]+1,edge[i].to)),vis[edge[i].to]=1;
            }
    }
}

int main()
{
    n=read();m=read();q=read();
    rp(i,1,m)a[i]=read(),b[i]=read();
    rp(i,1,q)r[q-i+1]=read(),lq[r[q-i+1]]=1;
    rp(i,1,m)if(lq[i]==0)add(a[i],b[i]),add(b[i],a[i]);
    dij();
    rp(i,1,q)
    {
        add(a[r[i]],b[r[i]]);add(b[r[i]],a[r[i]]);
        if(abs(dis[a[r[i]]]-dis[b[r[i]]])>1)
        {
            ans=1;
            if(dis[a[r[i]]]>dis[b[r[i]]])dis[a[r[i]]]=dis[b[r[i]]]+1,update(a[r[i]],i);
            else dis[b[r[i]]]=dis[a[r[i]]]+1,update(b[r[i]],i);
            f[i]+=ans;
        }
    }
    my(i,q,2)f[i-1]+=f[i];
    my(i,q,1)printf("%lld\n",f[i]);
    return 0;
}
删删改改3h最后T了的傻逼代码QAQ

然后正解其实还挺好理解的,就是其实我的想法比较接近正解了?但是我的这个太麻烦了嘛,我其实并不需要能改变就改变,而是能改成最短路的时候再改变这样就可以一步到位不需要再搞些改变f之类的傻逼操作

好的那就这样我还是觉得比较好理解应该已经讲通了?

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll int
#define rp(i,x,y) for(register ll i=x;i<=y;++i)
#define my(i,x,y) for(register ll i=x;i>=y;--i)
#define P pair<ll,ll>
#define mp make_pair

const ll M=1000000+10;
ll n,m,q,head[M],a[M],b[M],r[M],tot,dis1[M],dis2[M],ans,f[M];
bool lq[M],vis[M];
struct ed{ll to,next;}edge[M<<1];
priority_queue< P,vector< P >,greater< P > >Q;

inline ll read()
{
    char ch=getchar();ll x=0;bool y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=getchar();
    if(ch=='-')ch=getchar(),y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
    return y?x:-x;
}
inline void add(ll x,ll y){edge[++tot].to=x;edge[tot].next=head[y];head[y]=tot;}
inline void dij1()
{
    memset(dis1,127/3,sizeof(dis1));Q.push(mp(0,1));vis[1]=1;dis1[1]=0;
    while(!Q.empty())
    {
        ll t=Q.top().second;Q.pop();
        for(ll i=head[t];i!=0;i=edge[i].next)
            if(dis1[edge[i].to]>dis1[t]+1){dis1[edge[i].to]=dis1[t]+1;if(!vis[edge[i].to])Q.push(mp(dis1[t]+1,edge[i].to)),vis[edge[i].to]=1;}
    }
}
inline void dij2()
{
    memset(dis2,127/3,sizeof(dis2));Q.push(mp(0,1));vis[1]=1;dis2[1]=0;
    while(!Q.empty())
    {
        ll t=Q.top().second;Q.pop();
        for(ll i=head[t];i!=0;i=edge[i].next)
            if(dis2[edge[i].to]>dis2[t]+1){dis2[edge[i].to]=dis2[t]+1;if(!vis[edge[i].to])Q.push(mp(dis2[t]+1,edge[i].to)),vis[edge[i].to]=1;}
    }
}
inline void update(ll u)
{
    for(ll i=head[u];i!=0;i=edge[i].next)
        if(dis1[edge[i].to]==dis1[u]+1 && dis1[edge[i].to]!=dis2[edge[i].to]){ans++;dis2[edge[i].to]=dis1[u]+1;update(edge[i].to);}
}

int main()
{
    n=read();m=read();q=read();
    rp(i,1,m)a[i]=read(),b[i]=read(),add(a[i],b[i]),add(b[i],a[i]);
    dij1();
    rp(i,1,q)r[q-i+1]=read(),lq[r[q-i+1]]=1;
    memset(vis,0,sizeof(vis));memset(head,0,sizeof(head));rp(i,1,tot)edge[i].to=edge[i].next=0;tot=0;
    rp(i,1,m)if(lq[i]==0)add(a[i],b[i]),add(b[i],a[i]);
    dij2();
    rp(i,1,q)
    {
        add(a[r[i]],b[r[i]]);add(b[r[i]],a[r[i]]);
        if( dis2[a[r[i]]]!=dis1[a[r[i]]] && dis2[b[r[i]]]==dis1[b[r[i]]] && dis2[b[r[i]]]+1==dis1[a[r[i]]] )
        {
            ans=1;dis2[a[r[i]]] = dis1[a[r[i]]];update(a[r[i]]);f[i]=ans;
        }//如果 b已经是最短路上a不是且可以更新
        if( dis2[b[r[i]]]!=dis1[b[r[i]]] && dis2[a[r[i]]]==dis1[a[r[i]]] && dis2[a[r[i]]]+1==dis1[b[r[i]]] )
        {
            ans=1;dis2[b[r[i]]] = dis1[b[r[i]]];update(b[r[i]]);f[i]=ans;
        }//反之亦然咯
    }
    my(i,q,2)f[i-1]+=f[i];
    my(i,q,1)printf("%d\n",f[i]);
    return 0;
}
View Code

 


 

然后真的忍不住吐槽一下...这辣鸡题目...我实打实搞了应该有5h?我都快疯了...

我,先是加边加成单向,0了4次

然后计算答案的时候是从n算到1而不是从q算到1,70了3次

然后尝试开大空间MLE了,20了2次

然后又去调之前的方法TLE了,80了一次

...有点心酸,最近是不是运气不太好QAQ

猜你喜欢

转载自www.cnblogs.com/lqsukida/p/9883691.html