洛谷P1710 地鐵漲價 圖論
阿新 • • 發佈:2018-10-31
其實是個傻逼題但是我太傻逼了然後就錯了無數遍總算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刪刪改改3h最後T了的傻逼程式碼QAQmp 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; }
然後正解其實還挺好理解的,就是其實我的想法比較接近正解了?但是我的這個太麻煩了嘛,我其實並不需要能改變就改變,而是能改成最短路的時候再改變這樣就可以一步到位不需要再搞些改變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