Codeforces Gym 102059 部分题题解
(具体题解慢慢完善)
A.Coloring Roads
题目链接
简要题解
这道题看起来挺可做,因为约束条件挺强的,每次都是染色从某个点到根的一条路径。
不如做一个大胆猜想:每次需要修改的路径上均摊只有大约\(logn\)种不同的颜色。
既然是维护树上路径,我们不难想到树链剖分。
将轻重链划分之后,每条重链维护一个单调栈,栈内存的是这条重链上的颜色段,栈顶到栈底的颜色深度单增。
对于每次修改,我们跳重链,每到一条重链,就把栈内小于当前点深度的颜色全部弹掉,然后把当前点的颜色和深度加入栈内。
修改栈的过程中,直接用桶维护每种颜色有几条链,以及含有几条链的颜色有几种。
分析一下,每次修改最多给栈内加入\(logn\)个元素,因此弹栈和入栈的总次数是\(O(n*logn)\)级别的,树链剖分每次也是\(logn\)级别的
总时间复杂度为\(O(n*logn)\)
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
struct EDGE{ int u,v,Next; }Edge[MAXN*2];
int n,C,Qs,Es,First[MAXN];
int Tong[MAXN],Cnt[MAXN];
int Read()
{ int a=0,c=1; char b=getchar();
while(b!='-'&&(b<'0'||b>'9')) b=getchar();
if(b=='-') c=-1,b=getchar();
while(b>='0'&&b<='9') a=a*10+b-48,b=getchar();
return a*c;
}
void Link(int u,int v){ Edge[++Es]=(EDGE){u,v,First[u]},First[u]=Es; }
void Add(int Nc,int Num){ Tong[Cnt[Nc]]--,Cnt[Nc]+=Num,Tong[Cnt[Nc]]++; }
namespace Heavy
{ struct ELE{ int C,D; };
int Ds,Dfn[MAXN],Tot[MAXN],Son[MAXN],Old[MAXN],Top[MAXN],Fa[MAXN],Deep[MAXN];
stack<ELE>Stk[MAXN];
void Dfs1(int Now,int Ba)
{ Tot[Now]=1,Fa[Now]=Ba,Deep[Now]=Deep[Ba]+1;
for(int i=First[Now],v;i!=-1;i=Edge[i].Next)
{ if((v=Edge[i].v)==Ba) continue ;
Dfs1(v,Now),Tot[Now]+=Tot[v];
if(Tot[v]>Tot[Son[Now]]) Son[Now]=v;
}
}
void Dfs2(int Now,int Topf)
{ Dfn[Now]=++Ds,Top[Ds]=Topf;
if(Son[Now]) Dfs2(Son[Now],Topf);
for(int i=First[Now],v;i!=-1;i=Edge[i].Next)
if((v=Edge[i].v)!=Fa[Now]&&v!=Son[Now]) Dfs2(v,Ds+1);
}
void Modify(int Bot,int Nc)
{ int Nt=0,Nd;
for(Bot=Dfn[Bot];Bot!=1;Bot=Dfn[Fa[Old[Top[Bot]]]])
{ Nt=Top[Bot]+(Top[Bot]==1),Nd=Deep[Old[Nt]]-1;
for(ELE Up;!Stk[Nt].empty();)
{ Up=Stk[Nt].top();
if(Up.D<=Deep[Old[Bot]]) Add(Up.C,Nd-Up.D),Nd=Up.D,Stk[Nt].pop();
else
{ Add(Up.C,Nd-Deep[Old[Bot]]);
break ;
}
}
Stk[Nt].push((ELE){Nc,Deep[Old[Bot]]}),Add(Nc,Deep[Old[Bot]]-Deep[Old[Nt]]+1);
}
}
}using namespace Heavy;
int main()
{ n=Read(),C=Read(),Qs=Read(),Tong[0]=C;
memset(First,-1,sizeof(First));
for(int i=1,A,B;i<=n-1;i++) A=Read(),B=Read(),Link(A,B),Link(B,A);
Dfs1(1,1),Dfs2(1,1);
for(int i=1;i<=n;i++) Old[Dfn[i]]=i;
for(int i=1,A,B,C;i<=Qs;i++) A=Read(),B=Read(),C=Read(),Modify(A,B),printf("%d\n",Tong[C]);
}
D.Dumae
题目链接
简要题解
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=3e5+10;
struct ELE{ int Id,Ri; }Top;
struct SEC{ int Le,Ri; }Sec[MAXN];
int n,m,Os,Ord[MAXN],Deg[MAXN],Ans[MAXN];
vector<int>Aft[MAXN];
vector<ELE>Seq[MAXN];
queue<int>Team;
priority_queue<ELE>Heap;
int Read()
{ int a=0,c=1; char b=getchar();
while(b!='-'&&(b<'0'||b>'9')) b=getchar();
if(b=='-') c=-1,b=getchar();
while(b>='0'&&b<='9') a=a*10+b-48,b=getchar();
return a*c;
}
int Min(int A,int B){ return A<B?A:B; }
int Max(int A,int B){ return A>B?A:B; }
bool operator <(ELE A,ELE B){ return A.Ri>B.Ri; }
void Toposort()
{ for(int i=1;i<=n;i++)
if(!Deg[i]) Team.push(i);
for(int Now;!Team.empty();)
{ Now=Team.front(),Team.pop(),Ord[++Os]=Now;
for(int v:Aft[Now])
if((--Deg[v])==0) Team.push(v);
}
if(Os<n) puts("-1"),exit(0);
}
void Solve()
{ for(int i=n,Now;i>=1;i--)
{ Now=Ord[i];
for(int v:Aft[Now]) Sec[Now].Ri=Min(Sec[Now].Ri,Sec[v].Ri-1);
}
for(int i=1,Now;i<=n;i++)
{ Now=Ord[i];
for(int v:Aft[Now]) Sec[v].Le=Max(Sec[v].Le,Sec[Now].Le+1);
}
for(int i=1;i<=n;i++) Seq[Sec[i].Le].push_back((ELE){i,Sec[i].Ri});
for(int i=1;i<=n;i++)
{ for(ELE j:Seq[i]) Heap.push(j);
if(Heap.empty()) puts("-1"),exit(0);
Top=Heap.top(),Heap.pop();
if(Top.Ri<i) puts("-1"),exit(0);
Ans[i]=Top.Id;
}
}
int main()
{ n=Read(),m=Read();
for(int i=1;i<=n;i++) Sec[i].Le=Read(),Sec[i].Ri=Read();
for(int i=1,A,B;i<=m;i++) A=Read(),B=Read(),Aft[A].push_back(B),Deg[B]++;
Toposort(),Solve();
for(int i=1;i<=n;i++) printf("%d\n",Ans[i]);
}
E.Electronic Circuit
题目链接
简要题解
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
int n,m,Ans,Vis[MAXN];
set<int>Edge[MAXN];
queue<int>Team;
int Read()
{ int a=0,c=1; char b=getchar();
while(b!='-'&&(b<'0'||b>'9')) b=getchar();
if(b=='-') c=-1,b=getchar();
while(b>='0'&&b<='9') a=a*10+b-48,b=getchar();
return a*c;
}
void Bfs()
{ for(int i=1;i<=n;i++)
if(Edge[i].size()==2) Team.push(i),Vis[i]=1;
for(int Now,A,B;!Team.empty();)
{ Now=Team.front(),Team.pop();
if(Edge[Now].size()!=2) continue ;
A=*Edge[Now].begin(),Edge[A].erase(Now),B=*Edge[Now].rbegin();
Edge[B].erase(Now),Edge[A].insert(B),Edge[B].insert(A),Edge[Now].clear();
if(Edge[A].size()==2&&!Vis[A]) Team.push(A),Vis[A]=1;
if(Edge[B].size()==2&&!Vis[B]) Team.push(B),Vis[B]=1;
}
}
int main()
{ n=Read(),m=Read();
for(int i=1,A,B;i<=m;i++) A=Read(),B=Read(),Edge[A].insert(B),Edge[B].insert(A);
Bfs();
for(int i=1;i<=n;i++)
if(Edge[i].size()>1) return puts("No");
else Ans+=(Edge[i].size()==1);
puts(Ans==2?"Yes":"No");
}
F.Fake Plastic Trees
题目链接
简要题解
代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n;
int T,Ans,Ts,Lson[1010],Rson[1010];
map<ll,int>Map;
int Build(ll Num)
{ if(Map.find(Num)!=Map.end()) return Map[Num];
ll Hf=Num/2,Nr=Build(Hf),Nl=Build(Num-Hf),Nd=++Ts;
return Lson[Nd]=Nl,Rson[Nd]=Nr,Map[Num]=Nd;
}
int main()
{ for(scanf("%d",&T);T;T--)
{ scanf("%lld",&n),Ts=0,Map.clear(),Map[1]=0,Lson[0]=Rson[0]=-1;
Ans=Build(n),printf("%d\n",Ts+1);
for(int i=0;i<=Ts;i++) printf("%d %d\n",Lson[i],Rson[i]);
printf("%d\n",Ans);
}
}
G.Fascination Street
题目链接
简要题解
代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=25e4+10;
const ll Inf=1e18;
int n,K,W[MAXN];
ll Ans=Inf,F[MAXN][11][11][4];
int Read()
{ int a=0,c=1; char b=getchar();
while(b!='-'&&(b<'0'||b>'9')) b=getchar();
if(b=='-') c=-1,b=getchar();
while(b>='0'&&b<='9') a=a*10+b-48,b=getchar();
return a*c;
}
ll Min(ll A,ll B){ return A<B?A:B; }
int main()
{ n=Read(),K=Read();
memset(F,0X7f,sizeof(F));
for(int i=1;i<=n;i++) W[i]=Read();
F[0][0][0][2]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<=K;j++)
for(int k=0;k<=K;k++)
for(int l=0,St;l<=3;l++)
{ if(l)
{ St=l<<1&3,F[i][j][k][St]=Min(F[i][j][k][St],F[i-1][j][k][l]);
F[i][j+1][k][St]=Min(F[i][j+1][k][St],F[i-1][j][k][l]+W[i]);
}
St=l<<1&3|1,F[i][j][k][St]=Min(F[i][j][k][St],F[i-1][j][k][l]+W[i]);
F[i][j][k+1][St]=Min(F[i][j][k+1][St],F[i-1][j][k][l]);
}
for(int i=0;i<=K;i++)
for(int j=1;j<=3;j++) Ans=Min(Ans,F[n][i][i][j]);
printf("%lld\n",Ans);
}
I.Game on Plane
题目链接
简要题解
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=5010;
int T,n,SG[MAXN],Get[MAXN];
int main()
{ for(int i=2;i<=5000;i++)
{ for(int j=0,k=i-2;j<=k;j++,k--) Get[SG[j]^SG[k]]=1;
for(int j=0;j<=5000;j++)
if(!Get[j]) SG[i]=j,j=5000;
for(int j=0,k=i-2;j<=k;j++,k--) Get[SG[j]^SG[k]]=0;
}
for(scanf("%d",&T);T;T--)
scanf("%d",&n),puts(SG[n]?"First":"Second");
}
M.Utilitarianism
题目链接
简要题解
代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN=25e4+10;
const ll Inf=1e18;
struct EDGE{ int u,v,Next; ll w; }Edge[MAXN*2];
int n,K,Es,Get,First[MAXN],Fs[MAXN][2];
ll Ans,F[MAXN][2];
int Read()
{ int a=0,c=1; char b=getchar();
while(b!='-'&&(b<'0'||b>'9')) b=getchar();
if(b=='-') c=-1,b=getchar();
while(b>='0'&&b<='9') a=a*10+b-48,b=getchar();
return a*c;
}
ll Max(ll A,ll B){ return A>B?A:B; }
void Link(int u,int v,ll w){ Edge[++Es]=(EDGE){u,v,First[u],w},First[u]=Es; }
void Trans(ll &N0,int &Ns0,ll &N1,int &Ns1,ll &V0,int &Vs0,ll &V1,int &Vs1,ll &w)
{ ll B; int Bs;
if(V0==V1) B=V0,Bs=Max(Vs0,Vs1);
else V0>V1?(B=V0,Bs=Vs0):(B=V1,Bs=Vs1);
N1+=B,Ns1+=Bs;
if(N1<N0+V0+w) N1=N0+V0+w,Ns1=Ns0+Vs0+1;
else if(N1==N0+V0+w&&Ns1<Ns0+Vs0+1) Ns1=Ns0+Vs0+1;
N0+=B,Ns0+=Bs;
}
void Dfs(int Now,int Ba)
{ for(int i=First[Now],v;i!=-1;i=Edge[i].Next)
{ if((v=Edge[i].v)==Ba) continue ;
Dfs(v,Now),Trans(F[Now][0],Fs[Now][0],F[Now][1],Fs[Now][1],F[v][0],Fs[v][0],F[v][1],Fs[v][1],Edge[i].w);
}
}
int Check(ll Rate)
{ for(int i=1;i<=Es;i++) Edge[i].w-=Rate;
for(int i=1;i<=n;i++) F[i][0]=0,F[i][1]=-Inf,Fs[i][0]=Fs[i][1]=0;
Dfs(1,1);
for(int i=1;i<=Es;i++) Edge[i].w+=Rate;
return F[1][0]<F[1][1]?Fs[1][1]>=K:Fs[1][0]>=K;
}
int main()
{ n=Read(),K=Read();
memset(First,-1,sizeof(First));
for(int i=1,u,v,w;i<n;i++) u=Read(),v=Read(),w=Read(),Link(u,v,w),Link(v,u,w);
for(ll Le=-1e12,Ri=1e12,Mid;Le<=Ri;)
Mid=(Le+Ri)/2,Check(Mid)?(Ans=Max(F[1][0],F[1][1])+Mid*K,Get=1,Le=Mid+1):Ri=Mid-1;
Get?printf("%lld\n",Ans):puts("Impossible");
}