CTYZ的树论赛(P5557 旅行/P5558 心上秋/P5559 失昼城的守星使)
Posted y2823774827y
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CTYZ的树论赛(P5557 旅行/P5558 心上秋/P5559 失昼城的守星使)相关的知识,希望对你有一定的参考价值。
总结
由于受中秋节影响,没能在比赛时间内切掉\(T3\)
思维难度\(T1<T2<T3\),代码难度\(T1>T2>T3\)
P5557 旅行
显然跳到环上去后就可以直接模了,所以一遍遍历找到每个点是否在环上
如在环上求出环上\(len\),如不在求出到环还需走的长度\(Len\),预处理出每个点走\(2^i\)的位置
\(t1^t2\)由于过大不能直接求,在快速幂的同时求出判断大于\(Len\)
大于先记录,另走到环上,最终落在环上的位置距离环头为\(x\equiv t1^t2-Len(mod~len)\)
小于说明该数并不大,直接倍增走
#include<bits/stdc++.h>
typedef long long LL;
const LL maxn=400009;
inline LL Read()
LL x(0),f(1); char c=getchar();
while(c<'0' || c>'9')
if(c=='-') f=-1; c=getchar();
while(c>='0' && c<='9')
x=(x<<3ll)+(x<<1ll)+c-'0'; c=getchar();
return x*f;
LL n,m,top,tim;
LL a[maxn],f[maxn][21],seed[21],visit[maxn],len[maxn],sta[maxn],dep[maxn],Len[maxn],dfn[maxn];
inline LL Pow(LL base,LL b,LL mod)
LL ret(1);
while(b)
if(b&1) ret=1ll*ret*base%mod;
base=1ll*base*base%mod; b>>=1;
return ret;
void Dfs1(LL u)
sta[++top]=u; dfn[u]=++tim;
LL v(a[u]);
visit[u]=1;
if(visit[v] && !Len[v])
len[u]=dep[u]-dep[v]+1;
LL now;
do
now=sta[top--]; len[now]=len[u]; visit[now]=false;
while(now!=v);
return;
dep[v]=dep[u]+1;
if(!dfn[v]) Dfs1(v);
if(!len[u])
Len[u]=Len[v]+1;
int main()
n=Read();
for(LL i=1;i<=n;++i) a[i]=Read(),f[i][0]=a[i];
for(LL i=1;i<=n;++i)
if(!dfn[i]) dep[i]=0,Dfs1(i);
for(LL j=1;j<=20;++j)
for(LL i=1;i<=n;++i)
f[i][j]=f[f[i][j-1]][j-1];
seed[0]=1;
for(LL i=1;i<=20;++i) seed[i]=seed[i-1]*2;
m=Read();
while(m--)
LL s(Read()),t1(Read()),t2(Read()),now1(s);
if(Len[s])
LL base(t1),b(t2),R(1),flag(0),tmp(Len[s]);
while(b)
if(b&1)
R=R*base;
if(R>tmp)
flag=true; break;
base=base*base;
if(b!=1)
if(base>tmp)
flag=1; break;
b>>=1;
if(!flag)
tmp=R;
for(LL i=20;i>=0;--i)
if(tmp>=seed[i])
tmp-=seed[i]; now1=f[now1][i];
if(!tmp)
printf("%lld\n",now1); break;
continue;
else
for(LL i=20;i>=0;--i)
if(tmp>=seed[i])
tmp-=seed[i]; now1=f[now1][i];
LL ret,now(now1);
ret=(Pow(t1,t2,len[now])-Len[s]%len[now]+len[now])%len[now];、
if(!ret)
printf("%lld\n",now); continue;
for(LL j=20;j>=0;--j)
if(ret>=seed[j])
ret-=seed[j],now=f[now][j];
if(!ret)
printf("%lld\n",now); break;
return 0;
P5558 心上秋
发现边颜色恒为正且小于\(5\),求得\(inc_i,j,c1,c2,low_i,j,c1,c2\)分别为\(i\)到\(i\)的\(2^j\)级祖先,子序列首\(c1\)尾\(c2\),单调不减/单调不增,的最长长度
对于每个查询,对\(x-lca\)把\(inc\)合起来,对\(y-lca\)把\(low\)合起来,然后在\(dp\)一遍即可
\(O(5^4(n+q)logn)\),由于转移的时候\(5^4\)卡不满,所以跑得不慢
#include<bits/stdc++.h>
typedef int LL;
const LL maxn=30009;
inline LL Read()
LL x(0),f(1); char c=getchar();
while(c<'0' || c>'9')
if(c=='-') f=-1; c=getchar();
while(c>='0' && c<='9')
x=(x<<3ll)+(x<<1ll)+c-'0'; c=getchar();
return x*f;
struct node
LL to,nxt,w;
dis[maxn<<1];
LL n,m,num;
LL head[maxn],f1[6][6],f2[6][6],inc[maxn][16][6][6],low[maxn][16][6][6],F[maxn][16],dep[maxn],tmp[6][6];
inline void Add(LL u,LL v,LL w)
dis[++num]=(node)v,head[u],w; head[u]=num;
void Dfs(LL u,LL f,LL c)
if(u!=1)
inc[u][0][c][c]=1; low[u][0][c][c]=1;
F[u][0]=f; for(LL i=1;i<=15;++i) F[u][i]=F[F[u][i-1]][i-1];
for(LL i=1;i<=15;++i)
for(LL j=1;j<=5;++j)
for(LL k=j;k<=5;++k)
for(LL jj=j;jj<=k;++jj)
for(LL kk=jj;kk<=k;++kk)
inc[u][i][j][k]=std::max(inc[u][i][j][k],inc[u][i-1][j][jj]+inc[F[u][i-1]][i-1][kk][k]);
for(LL i=1;i<=15;++i)
for(LL j=1;j<=5;++j)
for(LL k=1;k<=j;++k)
for(LL jj=k;jj<=j;++jj)
for(LL kk=k;kk<=jj;++kk)
low[u][i][j][k]=std::max(low[u][i][j][k],low[u][i-1][j][jj]+low[F[u][i-1]][i-1][kk][k]);
for(LL i=head[u];i;i=dis[i].nxt)
LL v(dis[i].to);
if(v==f) continue;
dep[v]=dep[u]+1;
Dfs(v,u,dis[i].w);
inline LL Lca(LL u,LL v)
if(dep[u]<dep[v]) std::swap(u,v);
for(LL i=15;i>=0;--i)
if(dep[F[u][i]]>=dep[v]) u=F[u][i];
if(u==v) return u;
for(LL i=15;i>=0;--i)
if(F[u][i]!=F[v][i]) u=F[u][i],v=F[v][i];
return F[u][0];
inline void Solve1(LL u,LL f)
memset(f1,0,sizeof(f1));
LL ret(dep[u]-dep[f]);
for(LL i=15;i>=0;--i)
if((ret&(1<<i))==(1<<i))
memcpy(tmp,f1,sizeof(f1));
memset(f1,0,sizeof(f1));
for(LL j=1;j<=5;++j)
for(LL k=j;k<=5;++k)
for(LL jj=j;jj<=k;++jj)
for(LL kk=jj;kk<=k;++kk)
f1[j][k]=std::max(f1[j][k],tmp[j][jj]+inc[u][i][kk][k]);
u=F[u][i];
inline void Solve2(LL u,LL f)
memset(f2,0,sizeof(f2));
LL ret(dep[u]-dep[f]);
for(LL i=15;i>=0;--i)
if((ret&(1<<i))==(1<<i))
memcpy(tmp,f2,sizeof(f2));
memset(f2,0,sizeof(f2));
for(LL j=1;j<=5;++j)
for(LL k=1;k<=j;++k)
for(LL jj=k;jj<=j;++jj)
for(LL kk=k;kk<=jj;++kk)
f2[j][k]=std::max(f2[j][k],tmp[j][jj]+low[u][i][kk][k]);
u=F[u][i];
int main()
n=Read();
for(LL i=1;i<n;++i)
LL u(Read()),v(Read()),w(Read());
Add(u,v,w); Add(v,u,w);
Dfs(1,0,0);
m=Read();
while(m--)
LL u(Read()),v(Read());
LL lca(Lca(u,v));
Solve1(u,lca); Solve2(v,lca);
LL ans(0);
for(LL i=1;i<=5;++i)
for(LL j=i;j<=5;++j)
for(LL ii=i;ii<=j;++ii)
for(LL jj=ii;jj<=j;++jj)
ans=std::max(ans,f1[i][ii]+f2[j][jj]);
printf("%d\n",ans);
return 0;
P5559 失昼城的守星使
题意:有边权树,初始点权均为\(1\),每次可对某个点点权取反/给出一个点对\((u,v)\)求该链每个点到其
以上是关于CTYZ的树论赛(P5557 旅行/P5558 心上秋/P5559 失昼城的守星使)的主要内容,如果未能解决你的问题,请参考以下文章