JZOJ 5794. 2018.08.10【2018提高组】模拟A组省选 旅行
Description
悠悠歲月,不知不覺,距那傳說中的pppfish晉級泡泡帝已是過 去數十年。數十年 中,這顆泡泡樹上,也是再度變得精彩,各種泡泡 天才輩出,驚艷世人,然而,似乎 不論后人如何的出彩,在他們的頭 頂之上,依然是有著一道身影而立。 泡泡帝,pppfish。 現在,pppfish即將帶著被自己收服的無數個泡泡怪前往下一個 空間,而在前往下 一個空間的道路上,有N個中轉站,和M條空間蟲洞連接中轉站(雙向通道,可有重 邊,可有環(huán)),然而,通過蟲洞 是要一定的條件的,pppfish將手下所有泡泡怪編號為 1,2 … +∞,對于每個空間蟲洞,有兩個值L和R,表示此蟲洞只允許編號從L到 R的泡 泡怪通過,pppfish現在在1號中轉站,他想帶盡可能多的泡 泡怪到達N號中轉站,于是 pppfish找到了機智的你,希望你告訴 他最多可以帶多少個泡泡怪,同時他還想知道所 有泡泡怪的編號(若 有多組解取字典序最小的一組 )
Input
第一行兩個用空格隔開的整數N,M(2<=N<=1000,0<=M<=3000) 接下來M行,每行四個用空格隔開的整數a,b,l,r 表示在a,b中轉站間有一個空間蟲洞允許編號l~r的泡泡怪通過。(1<=a, b<=N,1<=l<=r<=1e6
Output
第一行一個整數ans,表示最多能攜帶的泡泡怪數量 接下來一行ans個用空格隔開的正整數,表示泡泡怪的編號,從小到大依次輸出,如 果沒有泡泡怪能通過只要輸出“0”就可以了
Sample Input
Input1:
4 4
1 2 1 10
2 4 3 5
1 3 1 5
2 4 2 7
Input2:
2 2
1 2 1 3
1 2 4 6
Sample Output
Output1:
6
2 3 4 5 6 7
Output2:
3
1 2 3
Data Constraint
30%的數據 1 <= N,M <= 10
100%的數據 2 <= N <= 1000, 0 <= M <= 3000, 1 <= a, b <= N, 1 <= l <= r <= 10^6
Solution
本題最少有三種方法:最短路、LCT、并查集,我打了前兩種。
比賽的時候腦抽,居然不會做,比賽完十分鐘切。。
現將用最短路的方法,復雜度有點劣。
我們發(fā)現顯然答案區(qū)間肯定是邊權中出現過的數字。
那么我們枚舉答案左區(qū)間端點,只用符合條件的邊,
再從1號點跑最短路,這里邊權用右區(qū)間端點即可。
我用的是SPFA,時間復雜度為 O(N?M?K)O(N?M?K) 。
Code_1
#include<cstdio> #include<cstring> #include<algorithm> #include<cctype> using namespace std; const int N=1005; int n,m,tot,ans,num; int first[N],nex[N*6],en[N*6],wl[N*6],wr[N*6]; int a[N*3],q[N*N],dis[N]; bool bz[N]; inline int read() {int X=0,w=0; char ch=0;while(!isdigit(ch)) w|=ch=='-',ch=getchar();while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();return w?-X:X; } inline int min(int x,int y) {return x<y?x:y; } inline int max(int x,int y) {return x>y?x:y; } inline void insert(int x,int y,int l,int r) {nex[++tot]=first[x];first[x]=tot;en[tot]=y;wl[tot]=l;wr[tot]=r; } int main() {freopen("travel.in","r",stdin);freopen("travel.out","w",stdout);n=read(),m=read();int mn=1e6,mx=0;for(int i=1;i<=m;i++){int x=read(),y=read(),l=read(),r=read();a[i]=l;insert(x,y,l,r);insert(y,x,l,r);}sort(a+1,a+1+m);tot=unique(a+1,a+1+m)-(a+1);for(int i=1;i<=tot;i++){memset(dis,0,sizeof(dis));dis[q[1]=1]=1e6;int l=0,r=1;while(l<r){int x=q[++l];bz[x]=false;for(int j=first[x];j;j=nex[j])if(wl[j]<=a[i] && min(dis[x],wr[j])>dis[en[j]]){dis[en[j]]=min(dis[x],wr[j]);if(!bz[en[j]]) bz[q[++r]=en[j]]=true;}}if(dis[n]-a[i]+1>ans) ans=dis[n]-a[i]+1,num=a[i];}printf("%d\n",ans);for(int i=num;i<num+ans;i++) printf("%d ",i);return 0; }然而有更快的方法,那就是LCT,O(N?log?N)O(NlogN) 就可以了。
考慮維護最小生成樹,將邊按右區(qū)間端點從大到小加入,
LCT經典維護,邊權為左區(qū)間端點。
某一時刻若1和n連通,則看看此時能否更新答案即可。
Code2
#include<cstdio> #include<cstring> #include<algorithm> #include<cctype> using namespace std; const int N=1005; struct data {int x,y,l,r; }a[N*3]; int top,ans,beg; int fa[N<<2],s[N<<2][2],mx[N<<2],num[N<<2],st[N<<2]; bool rev[N<<2]; inline int read() {int X=0,w=0; char ch=0;while(!isdigit(ch)) w|=ch=='-',ch=getchar();while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();return w?-X:X; } void write(int x) {if(x>9) write(x/10);putchar(x%10+'0'); } inline bool cmp(data x,data y) {return x.r>y.r; } inline bool pd(int x) {return x==s[fa[x]][1]; } inline bool isroot(int x) {return x^s[fa[x]][0] && x^s[fa[x]][1]; } inline void modify(int x) {if(x) swap(s[x][0],s[x][1]),rev[x]^=1; } inline void down(int x) {if(rev[x]){modify(s[x][0]),modify(s[x][1]);rev[x]=false;} } inline void update(int x) {num[x]=mx[num[s[x][0]]]>mx[num[s[x][1]]]?num[s[x][0]]:num[s[x][1]];if(mx[x]>mx[num[x]]) num[x]=x; } inline void rotate(int x) {int y=fa[x],w=pd(x);if(s[y][w]=s[x][w^1]) fa[s[y][w]]=y;if((fa[x]=fa[y]) && !isroot(y)) s[fa[y]][pd(y)]=x;s[fa[y]=x][w^1]=y;update(y); } inline void splay(int x) {for(int y=st[top=1]=x;!isroot(y);y=fa[y]) st[++top]=fa[y];while(top) down(st[top--]);for(int y;!isroot(x);rotate(x))if(!isroot(y=fa[x])) rotate(pd(x)==pd(y)?y:x);update(x); } inline void access(int x) {for(int y=0;x;x=fa[y=x]) splay(x),s[x][1]=y,update(x); } inline void mkroot(int x) {access(x),splay(x),modify(x); } inline void link(int x,int y) {mkroot(x),fa[x]=y; } inline void cut(int x,int y) {mkroot(x),access(y),splay(y);s[y][0]=fa[x]=0; } inline int get(int x) {access(x),splay(x);int y=x;while(s[y][0]) y=s[y][0];return y; } int main() {freopen("travel.in","r",stdin);freopen("travel.out","w",stdout);int n=read(),m=read();for(int i=1;i<=m;i++) a[i].x=read(),a[i].y=read(),a[i].l=read(),a[i].r=read();sort(a+1,a+1+m,cmp);for(int i=1;i<=m;i++){int x=a[i].x,y=a[i].y,z=i+n;mx[num[z]=z]=a[i].l;if(get(x)^get(y)){link(x,z),link(z,y);}else{mkroot(x),access(y),splay(y);if(a[i].l<mx[num[y]]){int pos=num[y];cut(a[pos-n].x,pos),cut(pos,a[pos-n].y);link(x,z),link(z,y);}}if(get(1)==get(n)){mkroot(1),access(n),splay(n);if(a[i].r-mx[num[n]]+1>=ans) ans=a[i].r-mx[num[n]]+1,beg=mx[num[n]];}}write(ans),putchar('\n');for(int i=beg;i<beg+ans;i++) write(i),putchar(' ');return 0; }總結
以上是生活随笔為你收集整理的JZOJ 5794. 2018.08.10【2018提高组】模拟A组省选 旅行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ 4802: 欧拉函数(大数因数
- 下一篇: JZOJ 5820. 【NOIP提高A组