E. The Classic Problem
http://codeforces.com/problemset/problem/464/E
题意:给你一张无向带权图,求S-T的最短路,并输出路径。边权为2^xi。xi≤105,n≤105,m≤105.
想法:边权太大了,可以用数组按二进制存下来。带高精度跑太费事了。
观察一下,这里距离的更新:c=(a,b),用dis[a]更新dis[b]
①dis[b][c]=0,直接赋为1.只有一个数字改变。
②dis[b][c]=1,需要进位。考虑极端情况数据,xi都是一个数,那么需要进位O(m/2+m/4+m/8+...+1)≈O(m)
所以总改变次数为O(m),使用主席树维护这个二进制数组。
然后比较大小,可以在主席树上二分,如果左儿子一样就往右儿子走,反之走左儿子。判断是否一样可以用Hash。一次比较为O(logm).
于是dijkstra+heap+主席树:
空间复杂度O(mlogm).
时间复杂度O(mlog^2m).
ps:因为有进位要给主席树预留logm个空间。
1 #include<cstdio> 2 #include<algorithm> 3 const int len(110000),lem(8000000),HP(47),MP(666696667),RP(1000000007); 4 struct ChairManTree{int nx[2],sum;}tree[lem+10]; 5 int stot,root[len+10];int H[len+10],b[len+10],tp; 6 struct Node{int nd,nx,co;}bot[len*2+10]; 7 int tot,first[len+10]; 8 int n,m,v[len+10],u[len+10],x[len+10],axle[len+10],up,big,s,t,last[len+10]; 9 void add(int a,int b,int c){bot[++tot]=(Node){b,first[a],c};first[a]=tot;} 10 int two(int x) 11 { 12 int l=1,r=up,ans=1,mid; 13 while(l<=r) 14 if(axle[mid=(l+r)>>1]>=x){ans=mid;l=mid+1;}else r=mid-1; 15 return ans; 16 } 17 void update(int k,int l,int r) 18 { 19 tree[k].sum=(1ll*tree[tree[k].nx[0]].sum*H[(r-l+1)>>1]+tree[tree[k].nx[1]].sum)%MP; 20 } 21 void build(int k,int l,int r,int x) 22 { 23 if(l==r){tree[k].sum=x;return;} 24 int mid=(l+r)>>1; 25 tree[k].nx[0]=++stot;build(stot,l,mid,x); 26 tree[k].nx[1]=++stot;build(stot,mid+1,r,x); 27 update(k,l,r); 28 } 29 int cmp(int k1,int k2)//-:k1<k2,+:k2>k1,0:k1=k2,return +-pos 30 { 31 int l=1,r=up+1,mid; 32 while(l!=r) 33 { 34 mid=(l+r)>>1; 35 if(tree[tree[k1].nx[0]].sum==tree[tree[k2].nx[0]].sum) 36 k1=tree[k1].nx[1],k2=tree[k2].nx[1],l=mid+1; 37 else k1=tree[k1].nx[0],k2=tree[k2].nx[0],r=mid; 38 } 39 if(tree[k1].sum==tree[k2].sum)return 0; 40 if(tree[k1].sum<tree[k2].sum)return -l; 41 return l; 42 } 43 int insert(int k,int l,int r,int &x) 44 { 45 int z=++stot; 46 if(l==r) 47 { 48 if(tree[k].sum)tree[z].sum=0,x--;//进位 49 else tree[z].sum=1;return z; 50 } 51 int mid=(l+r)>>1,tmp;tree[z]=tree[k]; 52 if(x>mid){tmp=insert(tree[k].nx[1],mid+1,r,x);tree[z].nx[1]=tmp;} 53 if(x<=mid){tmp=insert(tree[k].nx[0],l,mid,x);tree[z].nx[0]=tmp;} 54 update(z,l,r); 55 return z; 56 } 57 void dfs(int x,int l,int r) 58 { 59 if(l==r){b[l]=tree[x].sum;return;} 60 int mid=(l+r)>>1; 61 dfs(tree[x].nx[0],l,mid); 62 dfs(tree[x].nx[1],mid+1,r); 63 } 64 struct data 65 { 66 int x,y; 67 bool operator <(const data &A)const//默认小根堆 68 { 69 return (cmp(x,A.x)>0); 70 } 71 }q[len*2+10];int qfree; 72 void Dijkstra() 73 { 74 for(int i=1;i<=n;i++)root[i]=root[n+1]; 75 root[s]=root[0];q[qfree=1]=(data){root[s],s}; 76 while(qfree) 77 { 78 data now=q[1];std::pop_heap(q+1,q+1+qfree);qfree--; 79 while(root[now.y]!=now.x&&qfree){now=q[1];std::pop_heap(q+1,q+1+qfree);qfree--;} 80 if(root[now.y]!=now.x&&!qfree)break; 81 for(int v=first[now.y];v;v=bot[v].nx) 82 { 83 int tmp=insert(root[now.y],1,up+1,bot[v].co); 84 int pos=cmp(tmp,root[bot[v].nd]); 85 if (pos>=0)continue; 86 last[bot[v].nd]=now.y; 87 root[bot[v].nd]=tmp; 88 q[++qfree]=(data){root[bot[v].nd],bot[v].nd}; 89 std::push_heap(q+1,q+1+qfree); 90 } 91 } 92 } 93 void put() 94 { 95 if(root[t]==root[n+1])printf("-1"); 96 else 97 { 98 if(tree[root[t]].sum==tree[root[0]].sum)printf("0\n"); 99 else 100 { 101 dfs(root[t],1,up+1); 102 int tmp=0,j=1,l=0; 103 for(int i=up;i>=1;i--) 104 { 105 while(l<axle[i]){l++;j=(j+j)%RP;} 106 tmp=(tmp+1ll*j*b[i])%RP; 107 } 108 printf("%d\n",tmp); 109 } 110 int now=t;b[tp=1]=t; 111 while(last[now]) 112 { 113 now=last[now]; 114 b[++tp]=now; 115 } 116 printf("%d\n",tp); 117 for(int i=tp;i>=1;i--) 118 printf("%d ",b[i]); 119 } 120 } 121 bool cmp2(int a,int b){return a>b;} 122 int main() 123 { 124 freopen("C.in","r",stdin); 125 freopen("C.out","w",stdout); 126 scanf("%d%d",&n,&m); 127 for(int i=1;i<=m;i++) 128 { 129 scanf("%d%d%d",v+i,u+i,x+i); 130 if(x[i]>big)big=x[i]; 131 } 132 scanf("%d%d",&s,&t); 133 for(int i=1;i<=big+40;i++)axle[i]=big+40-i;up=big+40; 134 H[0]=1;for(int i=1;i<=up+1;i++)H[i]=(1ll*H[i-1]*HP)%MP; 135 for(int i=1;i<=m;i++) 136 { 137 x[i]=two(x[i]); 138 add(v[i],u[i],x[i]); 139 add(u[i],v[i],x[i]); 140 } 141 root[0]=++stot;build(root[0],1,up+1,0);//zero 142 root[n+1]=++stot;build(root[n+1],1,up+1,1);//INF 143 Dijkstra(); 144 put(); 145 return 0; 146 }
时间: 2024-11-17 00:41:10