1 条题解

  • 0
    @ 2025-8-24 23:00:02

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar luanyanjia
    菜 -我ら是个と大に傻む逼なり-

    搬运于2025-08-24 23:00:02,当前版本为作者最后更新于2024-08-19 08:23:08,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    从题目名字看出此题需要用动态树解决。

    对于任意 ii,都有唯一的 pip_i 与之对应,由 pip_iii 连边,nn 种关系显然构成一基环树森林。对于环上的节点,一个点可以自己表示自己,所以可以直接解出该点的权值,其他点从环上的点直接推出即可。

    考虑如何动态维护这个过程,一个点上对应的线性变换显然可以用矩阵刻画(其实只是不想动脑子),对于一棵基环树,我们把它多出来那一条边,和根节点的答案都存在根节点上(这样的话换根就要慎重一些了),询问时直接链乘积求出系数即可。

    对于任意 Link(x,y)\text{Link}(x,y) 操作,若 x,yx,y 不连通则直接连边(注意此处 MakeRoot(x)\text{MakeRoot}(x) 也没有影响,因为能连出边的点一定不属于一棵基环树)。否则算出 xx 的答案,并把答案和这条边存在 xx 上。

    修改的时候,设此处原来的边为 (y,x)(y,x),现换为 (z,x)(z,x)。那么我们先 Cut(x,y)\text{Cut}(x,y)(此处根节点需要特判,因为它连向父亲的边没有真实连上),然后 Link(x,z)\text{Link}(x,z),最后如果 xx 不是根节点的话,要把 xx 所属的基环树的那条虚边再 Link\text{Link} 一遍(因为修改后环可能被拆了,此时应该将它真实连上以保证正确性)。

    最后关于无解和多解。可以证明,如果根无解,那么整棵树所有节点都无解,多解也有一样的性质。

    #include<bits/stdc++.h>
    using namespace std;
    inline void rd(){}
    template<typename T,typename ...U>
    inline void rd(T &x,U &...args){
    	char ch=getchar();
    	T f=1;x=0;
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    	x*=f;rd(args...);
    }
    const int N=3e4+5,mod=10007;
    struct Matrix{
    	int m[2][2];
    	Matrix(){memset(m,0,sizeof m);}
    	Matrix(int _x){memset(m,0,sizeof m);m[0][0]=m[1][1]=_x;}
    	Matrix friend operator+(Matrix a,Matrix b){
    		Matrix c;
    		for(int i=0;i<=1;i++)
    			for(int j=0;j<=1;j++)c.m[i][j]=(a.m[i][j]+b.m[i][j])%mod;
    		return c;
    	}
    	Matrix friend operator*(Matrix a,Matrix b){
    		Matrix c;
    		for(int i=0;i<=1;i++)
    			for(int j=0;j<=1;j++)
    				for(int k=0;k<=1;k++)(c.m[i][j]+=a.m[i][k]*b.m[k][j])%=mod;
    		return c;
    	}
    };
    inline int KSM(int x,int n){
    	int ans=1;
    	while(n){
    		if(n&1)ans=ans*x%mod;
    		x=x*x%mod;
    		n>>=1;
    	}
    	return ans;
    }
    int n,q;
    namespace LCT{
    	int f[N],ch[N][2],tag[N];
    	Matrix m[N],prd[N];
    	struct{int x,y,ans;}nd[N];
    	#define ls ch[p][0]
    	#define rs ch[p][1]
    	inline void PushUp(int p){prd[p]=prd[ls]*m[p]*prd[rs];}
    	inline void Rev(int p){
    		tag[p]^=1;swap(ls,rs);
    		PushUp(p);
    	}
    	inline void PushDown(int p){
    		if(!tag[p])return ;
    		Rev(ls),Rev(rs);tag[p]=0;
    	}
    	inline int Get(int p){return ch[f[p]][1]==p;}
    	inline int IsRoot(int p){return ch[f[p]][1]!=p&&ch[f[p]][0]!=p;}
    	void Update(int p){
    		if(!IsRoot(p))Update(f[p]);
    		PushDown(p);
    	}
    	inline void Rotate(int x){
    		int y=f[x],z=f[y],k=Get(x);
    		if(!IsRoot(y))ch[z][Get(y)]=x;
    		ch[y][k]=ch[x][!k],ch[x][!k]=y;
    		f[y]=x,f[x]=z,f[ch[y][k]]=y;
    		PushUp(y),PushUp(x);
    	}
    	inline void Splay(int x){
    		Update(x);
    		for(int fa=f[x];!IsRoot(x);Rotate(x),fa=f[x])
    			if(!IsRoot(fa))Rotate(Get(fa)==Get(x)?fa:x);
    	}
    	inline int Access(int x){
    		int p;
    		for(p=0;x;p=x,x=f[x])
    			Splay(x),ch[x][1]=p,PushUp(x);
    		return p;
    	}
    	inline void MakeRoot(int x){
    		x=Access(x);Rev(x);
    	}
    	inline int FindRoot(int p){
    		p=Access(p);
    		while(ls)p=ls,PushDown(p);
    		return Splay(p),p;
    	}
    	inline void Link(int x,int y){
    		if(FindRoot(x)==FindRoot(y)){
    			MakeRoot(x);Access(y);
    			Splay(x);Matrix mm=prd[ch[x][1]]*m[x];
    			nd[x].x=x,nd[x].y=y;
    			int k=(mm.m[0][0]+mod-1)%mod,b=mod-mm.m[1][0];
    			if(k==0&&b==0)nd[x].ans=-2;
    			else if(k==0)nd[x].ans=-1;
    			else nd[x].ans=1ll*b*KSM(k,mod-2)%mod;
    		}else{
    			MakeRoot(x);
    			Splay(x);f[x]=y;
    		}
    	}
    	inline void Modify(int x,int k,int y,int b){
    		int rt=FindRoot(x);
    		Splay(x);
    		m[x].m[0][0]=k,m[x].m[1][0]=b;
    		PushUp(x);
    		if(rt!=x){
    			Access(x);Splay(x);
    			f[ch[x][0]]=0,ch[x][0]=0;
    			Link(x,y);
    			Link(nd[rt].x,nd[rt].y);
    		}
    		else Link(x,y);
    	}
    	inline int Query(int p){
    		int rt=FindRoot(p);Access(p);
    		Splay(rt);
    		int k=prd[ch[rt][1]].m[0][0],b=prd[ch[rt][1]].m[1][0];
    		if(nd[rt].ans==-1)return -1;
    		if(nd[rt].ans==-2)return -2;
    		return (1ll*k*nd[rt].ans%mod+b)%mod;
    	}
    	#undef ls
    	#undef rs 
    }
    int p[N];
    using namespace LCT;
    signed main(){
    	rd(n);
    	prd[0]=m[0]=Matrix(1);
    	for(int i=1;i<=n;i++){
    		int k,b;rd(k,p[i],b);
    		m[i].m[0][0]=k;
    		m[i].m[1][0]=b;
    		m[i].m[1][1]=1;
    	}
    	for(int i=1;i<=n;i++)Link(i,p[i]);
    	rd(q);
    	while(q--){
    		char s[3];int a,x,y,z;
    		scanf("%s",s);
    		if(s[0]=='A'){
    			rd(a);
    			printf("%d\n",Query(a));
    		}else if(s[0]=='C'){
    			rd(a,x,y,z);
    			Modify(a,x,y,z);
    		}
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    10454
    时间
    1000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者