[NOI2018]归程(可持久化并查集,Kruskal重构树)

解法一:

  1.首先想到离线做法:将边和询问从大到小排序,并查集维护连通块以及每个连通块中所有点到1号点的最短距离。$O(n\log n)$

  配合暴力等可以拿到75分。

  2.很容易想到在线做法,使用可持久化并查集,询问时二分即可。

  不能使用路径压缩,应该按秩合并,注意秩是树的深度而不是大小。$O((E+Q)\log^2 N)$

  由于常数过大,基本过不去。

  3.考虑优化算法二,发现访问历史版本并不需要修改而只需要询问,所以一开始只使用普通的并查集,用可持久化数组记录并查集的修改情况。

  $O((N+E)\log N+Q\log^2 N)$,卡时通过。

  4.算法三的复杂度已经难以优化,考虑优化常数。不需要可持久化数据结构,直接对并查集的每个点用vector存下修改情况,询问时二分即可。

  $O(n\log^2 n)$,常数很小,轻松通过。

解法二:

  考虑Kruskal重构树,对海拔跑一次Kruskal同时对每条边新建一个节点,权值为边的海拔,并对每个点存下重构树的子树中到1号点的最小值。

  问题实际上是求一个点能通过走海拔不低于某个值的边到达的点中离1好号点最近的距离,也就是重构树上点权大于某个值的节点的子树中到1号点的最小值。倍增查询即可。

 1 #include<cstdio>
 2 #include<queue>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 6 using namespace std;
 7 
 8 const int N=1000010,inf=2000000000;
 9 bool b[N];
10 int n,m,T,q,K,S,v,p,cnt,Ans,mn[N],fa[N],ans[N],to[N],nxt[N],dis[N],val[N],h[N];
11 struct E{ int u,v,l,a; }e[N];
12 struct Que{ int v,p,id; }que[N];
13 struct P{ int x,d; };
14 bool operator <(const P &a,const P &b){ return a.d>b.d; }
15 priority_queue<P>Q;
16 
17 void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
18 int get(int x){ return (fa[x]==x) ? x : fa[x]=get(fa[x]); }
19 
20 bool cmp(E a,E b){ return a.a>b.a; }
21 bool cmp1(Que a,Que b){ return a.p>b.p; }
22 
23 void Dij(){
24     rep(i,1,n) dis[i]=inf,b[i]=0; dis[1]=0;
25     Q.push((P){1,0});
26     while (!Q.empty()){
27         int x=Q.top().x; Q.pop();
28         if (b[x]) continue;
29         b[x]=1;
30         for (int i=h[x],k; i; i=nxt[i])
31             if (!b[k=to[i]] && dis[k]>dis[x]+val[i])
32                 Q.push((P){k,dis[k]=dis[x]+val[i]});
33     }
34 }
35 
36 int main(){
37     freopen("return.in","r",stdin);
38     freopen("return.out","w",stdout);
39     for (scanf("%d",&T); T--; ){
40         scanf("%d%d",&n,&m);
41         rep(i,0,n) h[i]=0; cnt=0; Ans=0;
42         rep(i,1,m){
43             scanf("%d %d %d %d",&e[i].u,&e[i].v,&e[i].l,&e[i].a);
44             add(e[i].u,e[i].v,e[i].l); add(e[i].v,e[i].u,e[i].l);
45         }
46         sort(e+1,e+m+1,cmp); Dij();
47         scanf("%d%d%d",&q,&K,&S);
48         if (K){
49             rep(i,1,q){
50                 rep(i,1,n) mn[i]=dis[i],fa[i]=i;
51                 scanf("%d%d",&v,&p);
52                 v=(v+K*Ans-1)%n+1; p=(p+K*Ans)%(S+1); int st=1;
53                 while (e[st].a>p && st<=m){
54                     int u=get(e[st].u),v=get(e[st].v);
55                     if (u!=v){ fa[u]=v; mn[v]=min(mn[v],mn[u]); }
56                     st++;
57                 }
58                 printf("%d\n",Ans=mn[get(v)]);
59             }
60             continue;
61         }
62         rep(i,1,q) scanf("%d%d",&que[i].v,&que[i].p),que[i].id=i;
63         sort(que+1,que+q+1,cmp1); int st=1;
64         rep(i,1,n) mn[i]=dis[i],fa[i]=i;
65         rep(i,1,q){
66             while (e[st].a>que[i].p && st<=m){
67                 int u=get(e[st].u),v=get(e[st].v);
68                 if (u!=v){ fa[u]=v; mn[v]=min(mn[v],mn[u]); }
69                 st++;
70             }
71             ans[que[i].id]=mn[get(que[i].v)];
72         }
73         rep(i,1,q) printf("%d\n",ans[i]);
74     }
75     return 0;
76 }
75分
 1 #include<queue>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<algorithm>
 5 #define pb push_back
 6 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 7 using namespace std;
 8 
 9 const int N=400010,inf=2000000000;
10 bool b[N];
11 int n,m,q,k,s,T,ans,cnt,dis[N],fa[N],mn[N],h[N],dep[N],to[N<<1],val[N<<1],nxt[N<<1];
12 struct E{ int u,v,l,a; }e[N];
13 struct S{ int p,v; };
14 struct P{ int x,d; };
15 bool operator <(const E &a,const E &b){ return a.a>b.a; }
16 bool operator <(const P &a,const P &b){ return a.d>b.d; }
17 bool operator <(const S &a,const S &b){ return a.p>b.p; }
18 vector<S>Fa[N],Mn[N];
19 priority_queue<P>Q;
20 
21 void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
22 int find(int x){ return (x==fa[x]) ? x : find(fa[x]); }
23 
24 void Dij(){
25     rep(i,1,n) dis[i]=inf,b[i]=0; dis[1]=0; Q.push((P){1,0});
26     while (!Q.empty()){
27         int x=Q.top().x; Q.pop();
28         if (b[x]) continue;
29         b[x]=1;
30         for (int i=h[x],k; i; i=nxt[i])
31             if (!b[k=to[i]] && dis[k]>dis[x]+val[i])
32                 Q.push((P){k,dis[k]=dis[x]+val[i]});
33     }
34 }
35 
36 void init(){
37     cnt=0; while (!Q.empty()) Q.pop();
38     rep(i,1,n) h[i]=0,Fa[i].clear(),Mn[i].clear();
39 }
40 
41 void work(){
42     scanf("%d%d",&n,&m);
43     rep(i,1,m){
44         scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].l,&e[i].a);
45         add(e[i].u,e[i].v,e[i].l); add(e[i].v,e[i].u,e[i].l);
46     }
47     Dij(); sort(e+1,e+m+1);
48     rep(i,1,n) Fa[i].pb((S){inf,fa[i]=i}),Mn[i].pb((S){inf,mn[i]=dis[i]}),dep[i]=1;
49     rep(i,1,m){
50         int p=e[i].a,u=find(e[i].u),v=find(e[i].v);
51         if (u==v) continue;
52         if (dep[u]>dep[v]) swap(u,v);
53         fa[u]=v; dep[v]=max(dep[u]+1,dep[v]); mn[v]=min(mn[v],mn[u]);
54         Fa[u].pb((S){p,fa[u]}); Mn[v].pb((S){p,mn[v]});
55     }
56     scanf("%d%d%d",&q,&k,&s); ans=0;
57     rep(i,1,q){
58         int v,p; scanf("%d%d",&v,&p); v=(v+k*ans-1)%n+1; p=(p+k*ans)%(s+1);
59         for (int f; v!=(f=(--lower_bound(Fa[v].begin(),Fa[v].end(),(S){p,0}))->v); v=f);
60         printf("%d\n",ans=(--lower_bound(Mn[v].begin(),Mn[v].end(),(S){p,0}))->v);
61     }
62 }
63 
64 int main(){
65     freopen("return.in","r",stdin);
66     freopen("return.out","w",stdout);
67     for (scanf("%d",&T); T--; ) init(),work();
68     return 0;
69 }
解法一
 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 6 using namespace std;
 7 
 8 const int N=400010,inf=2000000000;
 9 bool b[N];
10 int n,m,q,K,v,p,S,T,ans,tot,cnt,dis[N],fa[N],s[N],mn[N],h[N],Fa[N][21],to[N<<1],val[N<<1],nxt[N<<1];
11 struct E{ int u,v,l,a; }e[N];
12 struct P{ int x,d; };
13 bool operator <(const P &a,const P &b){ return a.d>b.d; }
14 bool operator <(const E &a,const E &b){ return a.a>b.a; }
15 priority_queue<P>Q;
16 
17 void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
18 int find(int x){ return (x==fa[x]) ? x : fa[x]=find(fa[x]); }
19 
20 void Dij(){
21     rep(i,1,n) dis[i]=inf,b[i]=0; dis[1]=0; Q.push((P){1,0});
22     while (!Q.empty()){
23         int x=Q.top().x; Q.pop();
24         if (b[x]) continue;
25         b[x]=1;
26         for (int i=h[x],k; i; i=nxt[i])
27             if (!b[k=to[i]] && dis[k]>dis[x]+val[i])
28                 Q.push((P){k,dis[k]=dis[x]+val[i]});
29     }
30 }
31 
32 void dfs(int x){
33     if (x>n) mn[x]=inf; else mn[x]=dis[x];
34     for (int i=h[x],k; i; i=nxt[i])
35         Fa[k=to[i]][0]=x,dfs(k),mn[x]=min(mn[x],mn[k]);
36 }
37 
38 void Kruskal(){
39     rep(i,1,n) h[i]=0; cnt=0; tot=n;
40     rep(i,1,n) fa[i]=i;
41     rep(i,1,m){
42         int u=find(e[i].u),v=find(e[i].v);
43         if (u==v) continue;
44         s[++tot]=e[i].a; fa[u]=fa[v]=fa[tot]=tot;
45         add(tot,u,0); add(tot,v,0);
46     }
47     dfs(tot);
48 }
49 
50 void work(){
51     scanf("%d%d",&n,&m);
52     rep(i,1,m){
53         scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].l,&e[i].a);
54         add(e[i].u,e[i].v,e[i].l); add(e[i].v,e[i].u,e[i].l);
55     }
56     Dij(); sort(e+1,e+m+1); Kruskal();
57     rep(i,1,20) rep(x,1,tot) Fa[x][i]=Fa[Fa[x][i-1]][i-1];
58     scanf("%d%d%d",&q,&K,&S); ans=0;
59     while (q--){
60         scanf("%d%d",&v,&p);
61         v=(v+K*ans-1)%n+1; p=(p+K*ans)%(S+1);
62         for (int i=20; ~i; i--) if (Fa[v][i] && s[Fa[v][i]]>p) v=Fa[v][i];
63         printf("%d\n",ans=mn[v]);
64     }
65 }
66 
67 void init(){ cnt=0; memset(Fa,0,sizeof(Fa)); memset(h,0,sizeof(h)); }
68 
69 int main(){
70     freopen("return.in","r",stdin);
71     freopen("return.out","w",stdout);
72     for (scanf("%d",&T); T--; ) init(),work();
73     return 0;
74 }
解法二

 

posted @ 2018-07-25 20:14  HocRiser  阅读(376)  评论(0编辑  收藏  举报