NOI2018部分题解

T1:归程

解法一:

  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 }
解法二

T4:屠龙勇士

  首先很明显剑的选择是唯一的,直接用multiset即可。

  接下来可以发现每条龙都是一个模线性方程。设攻击第i条龙的剑的攻击力为$s_i$,则$s_ix\equiv a_i\ (mod\ p_i)$。

  现在需要将方程化成$x\equiv c_i\ (mod\ m_i)$的形式,从而使用exCRT解决。

  变式:$s_ix+p_iy=a_i$,先同除以$gcd(s_i,p_i)$,再使用exgcd解不定方程,求x的最小正整数解。

  注意判无解,exCRT结束之后注意要使$x\geqslant max(\frac{a_i}{s_i})$

 1 #include<set>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=100010;
 9 multiset<ll>S;
10 bool mark;
11 int n,k,T;
12 ll mx,a[N],p[N],more[N],s[N],c[N],m[N];
13 
14 ll gcd(ll a,ll b){ return b ? gcd(b,a%b) : a; }
15 
16 ll mul(ll a,ll b,ll mod){
17     ll res=0; a%=mod; b%=mod;
18     for (; b; a=(a<<1)%mod,b>>=1)
19         if (b & 1) res=(res+a)%mod;
20     return res;
21 }
22 
23 void exgcd(ll a,ll b,ll &x,ll &y){
24     if (!b){ x=1; y=0; return; }
25     exgcd(b,a%b,y,x); y-=(a/b)*x;
26 }
27 
28 ll inv(ll a,ll b){ ll x,y; exgcd(a,b,x,y); x=(x%b+b)%b; return x; }
29 
30 bool merge(ll c1,ll c2,ll m1,ll m2,ll &c3,ll &m3){
31     ll d=gcd(m1,m2); m3=m1/d*m2;
32     if (c2<c1) swap(c1,c2),swap(m1,m2);
33     if ((c2-c1)%d) return 0;
34     c3=(mul(mul(inv(m1/d,m2/d),(c2-c1)/d,m2/d),m1,m3)+c1)%m3;
35     return 1;
36 }
37 
38 void work(){
39     scanf("%d%d",&n,&k); mark=1; mx=0; S.clear();
40     rep(i,1,n) scanf("%lld",&a[i]);
41     rep(i,1,n) scanf("%lld",&p[i]);
42     rep(i,1,n) scanf("%lld",&more[i]);
43     rep(i,1,k) scanf("%lld",&s[i]),S.insert(s[i]);
44     rep(i,1,n){
45         multiset<ll>::iterator it=S.upper_bound(a[i]);
46         if (it!=S.begin()) it--;
47         ll s=*it; S.erase(it); S.insert(more[i]);
48         mx=max(mx,(a[i]-1)/s+1);
49         ll d=gcd(s,p[i]);
50         if (a[i]%d) { mark=0; break; }
51         m[i]=p[i]/d; c[i]=mul(inv(s/d,m[i]),a[i]/d,m[i]);
52     }
53     if (!mark) { puts("-1"); return; }
54     rep(i,2,n) if (!merge(c[i-1],c[i],m[i-1],m[i],c[i],m[i])) { mark=0; break; }
55     if (!mark) { puts("-1"); return; }
56     if (c[n]<mx) c[n]+=((mx-c[n]-1)/m[n]+1)*m[n];
57     printf("%lld\n",c[n]);
58 }
59 
60 int main(){
61     freopen("dragon.in","r",stdin);
62     freopen("dragon.out","w",stdout);
63     for (scanf("%d",&T); T--; ) work();
64     return 0;
65 }
T4

 

猜你喜欢

转载自www.cnblogs.com/HocRiser/p/9365350.html