Codeforces 464E #265 (Div. 1) E. The Classic Problem 主席树+Hash

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 }

 

posted @ 2017-03-21 11:45  Oncle_Ha  阅读(435)  评论(1编辑  收藏  举报