• CTYZ的树论赛(P5557 旅行/P5558 心上秋/P5559 失昼城的守星使)


    总结

    由于受中秋节影响,没能在比赛时间内切掉(T3)

    思维难度(T1<T2<T3),代码难度(T1>T2>T3)

    P5557 旅行

    显然跳到环上去后就可以直接模了,所以一遍遍历找到每个点是否在环上

    如在环上求出环上(len),如不在求出到环还需走的长度(Len),预处理出每个点走(2^i)的位置

    (t1^t2)由于过大不能直接求,在快速幂的同时求出判断大于(Len)

    • 大于先记录,另走到环上,最终落在环上的位置距离环头为(xequiv 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
    ",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
    ",now); continue;
    		}
    		for(LL j=20;j>=0;--j){
    			if(ret>=seed[j])
    			    ret-=seed[j],now=f[now][j];
    			if(!ret){
    				printf("%lld
    ",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
    ",ans);
    	}
    	return 0;
    }
    

    P5559 失昼城的守星使

    题意:有边权树,初始点权均为(1),操作可对某个点点权取反/给出一个点对((u,v))求该链每个正点到其链最短距离之和

    每个黑点到根的路径全部加一遍边权,显然可以用树链剖分维护,设(Dis(x,y))(x)(y)的边权和

    (S)为每个黑点到根的距离和,(tot)为黑点个数,(dep_x)(x)到根的距离

    (x=Lca(u,v)),答案为(S+tot*dep_lca-2*Dis(1,x)),这部分为(x)外的贡献剩下的为"下面"的到(x)的距离和

    再减去(Dis(x,y))则为最终答案

  • 相关阅读:
    绑定姿势
    Mesh.CombineMeshes
    Mono vs IL2CPP
    lua keynote2
    lua keynote
    游戏编程模式KeyNote
    架构、性能和游戏
    Canvas
    AssetBundle Manager
    Loading AssetBundle Manifests
  • 原文地址:https://www.cnblogs.com/y2823774827y/p/11518248.html
Copyright © 2020-2023  润新知