BZOJ5415:[NOI2018]归程(可持久化并查集,最短路)

Description

Input

Output

Sample Input1

1
4 3
1 2 50 1
2 3 100 2
3 4 50 1
5 0 2
3 0
2 1
4 1
3 1
3 2

Sample Output1

0
50
200
50
150

Sample Input2

1
5 5
1 2 1 2
2 3 1 2
4 3 1 2
5 3 1 2
1 5 2 1
4 1 3
5 1
5 2
2 0
4 0

Sample Output2

0
2
3
1

HINT

Solution

会了可持久化并查集这题可能会被卡的正解就很好写了……

把边按高度大小从大到小加入,用可持久化并查集记下每一个时刻并查集的联通情况,

同时用持久化的$Min[i]$数组记录$i$点所在的连通块内到点$1$的最近距离。查询的时候二分到对应时刻的并查集直接查询就行了。

Code

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<queue>
  5 #include<algorithm>
  6 #define N (200009)
  7 using namespace std;
  8 
  9 struct Edge{int to,next,len;}edge[N<<2];
 10 struct Sgt{int ls,rs,v;};
 11 struct Line
 12 {
 13     int u,v,w,h;
 14     bool operator < (const Line &a) const {return h>a.h;}
 15 }l[N<<1];
 16 struct Node
 17 {
 18     int num,dis;
 19     bool operator < (const Node &a) const {return dis>a.dis;}
 20 };
 21 int T,n,m,u,v,w,h,q,k,s,v0,p0,ans;
 22 int dis[N],head[N],num_edge;
 23 bool vis[N];
 24 priority_queue<Node>Q;
 25 
 26 struct Chairman_Tree
 27 {
 28     Sgt a[N*40];
 29     int sgt_num,b[N],Root[N<<1];
 30     
 31     int Build(int l,int r)
 32     {
 33         int now=++sgt_num;
 34         if (l==r) {a[now].v=b[l]; return now;}
 35         int mid=(l+r)>>1;
 36         a[now].ls=Build(l,mid);
 37         a[now].rs=Build(mid+1,r);
 38         return now;
 39     }
 40     int Update(int pre,int l,int r,int x,int v)
 41     {
 42         int now=++sgt_num;
 43         a[now].ls=a[pre].ls;
 44         a[now].rs=a[pre].rs;
 45         if (l==r) {a[now].v=v; return now;}
 46         int mid=(l+r)>>1;
 47         if (x<=mid) a[now].ls=Update(a[now].ls,l,mid,x,v);
 48         else a[now].rs=Update(a[now].rs,mid+1,r,x,v);
 49         return now;
 50     }
 51     int Query(int now,int l,int r,int x)
 52     {
 53         if (l==r) return a[now].v;
 54         int mid=(l+r)>>1;
 55         if (x<=mid) return Query(a[now].ls,l,mid,x);
 56         else return Query(a[now].rs,mid+1,r,x);
 57     }
 58 }Fa,Dep,Min;
 59 
 60 inline int read()
 61 {
 62     int x=0; char c=getchar();
 63     while (c<'0' || c>'9') c=getchar();
 64     while (c>='0' && c<='9') x=x*10+c-'0', c=getchar();
 65     return x;
 66 }
 67 
 68 void add(int u,int v,int w)
 69 {
 70     edge[++num_edge].to=v;
 71     edge[num_edge].next=head[u];
 72     edge[num_edge].len=w;
 73     head[u]=num_edge;
 74 }
 75 
 76 int Find(int x,int t)
 77 {
 78     int fa=Fa.Query(Fa.Root[t],1,n,x);
 79     return x==fa?x:Find(fa,t);
 80 }
 81 
 82 void Dijkstra(int s)
 83 {
 84     memset(dis,0x7f,sizeof(dis));
 85     memset(vis,0,sizeof(vis));
 86     dis[s]=0;
 87     Q.push((Node){s,0});
 88     while (!Q.empty())
 89     {
 90         int x=Q.top().num; Q.pop();
 91         if (vis[x]) continue; vis[x]=1;
 92         for (int i=head[x]; i; i=edge[i].next)
 93             if (!vis[edge[i].to] && dis[x]+edge[i].len<dis[edge[i].to])
 94             {
 95                 dis[edge[i].to]=dis[x]+edge[i].len;
 96                 Q.push((Node){edge[i].to,dis[edge[i].to]});
 97             }
 98     }
 99 }
100 
101 int main()
102 {
103     T=read();
104     while (T--)
105     {
106         Fa.sgt_num=Dep.sgt_num=Min.sgt_num=0;
107         memset(head,0,sizeof(head)); num_edge=0;
108         ans=0;
109         n=read(); m=read();
110         for (int i=1; i<=m; ++i)
111         {
112             u=read(); v=read(); w=read(); h=read();
113             l[i]=(Line){u,v,w,h};
114             add(u,v,w); add(v,u,w);
115         }
116         Dijkstra(1);
117         sort(l+1,l+m+1);
118         for (int i=1; i<=n; ++i)
119             Fa.b[i]=i, Dep.b[i]=1, Min.b[i]=dis[i];
120         Fa.Root[0]=Fa.Build(1,n);;
121         Dep.Root[0]=Dep.Build(1,n);
122         Min.Root[0]=Min.Build(1,n);
123         for (int i=1; i<=m; ++i)
124         {
125             Fa.Root[i]=Fa.Root[i-1];
126             Dep.Root[i]=Dep.Root[i-1];
127             Min.Root[i]=Min.Root[i-1];
128             int fx=Find(l[i].u,i),fy=Find(l[i].v,i);
129             if (fx==fy) continue;
130             int dfx=Dep.Query(Dep.Root[i],1,n,fx);
131             int dfy=Dep.Query(Dep.Root[i],1,n,fy);
132             if (dfx>dfy) swap(fx,fy);
133             Fa.Root[i]=Fa.Update(Fa.Root[i],1,n,fx,fy);
134             int d1=Min.Query(Min.Root[i],1,n,fx);
135             int d2=Min.Query(Min.Root[i],1,n,fy);
136             Min.Root[i]=Min.Update(Min.Root[i],1,n,fy,min(d1,d2));
137             if (dfx==dfy) Dep.Root[i]=Dep.Update(Dep.Root[i],1,n,fy,dfy+1);
138         }
139         q=read(); k=read(); s=read();
140         for (int i=1; i<=q; ++i)
141         {
142             v0=read(); p0=read();
143             v0=(v0+k*ans-1)%n+1;
144             p0=(p0+k*ans)%(s+1);
145             int L=1,R=m,A=-1;
146             while (L<=R)
147             {
148                 int mid=(L+R)>>1;
149                 if (l[mid].h>p0) A=mid,L=mid+1;
150                 else R=mid-1;
151             }
152             if (A==-1)
153             {
154                 printf("%d\n",dis[v0]);
155                 ans=dis[v0]; continue;
156             }
157             int fx=Find(v0,A);
158             ans=Min.Query(Min.Root[A],1,n,fx);
159             printf("%d\n",ans);
160         }
161     }
162 }
posted @ 2019-01-07 11:45  Refun  阅读(237)  评论(0编辑  收藏  举报