zoukankan      html  css  js  c++  java
  • BZOJ2759 一个动态树好题

    题目

    (N)个未知数(x[1..n])(N)个等式组成的同余方程组:
    (x[i]=k[i]*x[p[i]]+b[i] mod 10007)
    其中,(k[i],b[i],x[i]∈[0,10007)∩Z)
    你要应付(Q)个事务,每个是两种情况之一:
    一.询问当前(x[a])的解
    (A a)
    无解输出-1
    (x[a])有多解输出-2
    否则输出(x[a])
    二.修改一个等式
    (C a k[a] p[a] b[a])

    思路[1]

    此题一直有点迷,在paulliant大佬的指点下,勉强口胡一份题解。

    首先不难发现,这是一个树形结构,每个点仅有一条有向出边,知道了每个点的父亲就能知道这个点,所以这是一棵基环树,然后我们用一个结构体表示当前点与它父亲的依赖关系((K,B))表示(x=fa[x]*K+B)

    由于是单向边的有根树,所以每条边都指向它的父亲。所以对于LCT中的一条路径((u,v))来说,(sum[rt]=(node){K,B})表示(u=Kv+B),合并什么的还是很好推的。

    还有一题小R与手机和此题有几分相像。

    struct node{
    	int k,b;
    	node operator + (const node& res)const{
    		return (node){k*res.k%P,(res.k*b%P+res.b)%P};
    	}
    }
    

    然后如果存在了环的话,可以先把它存下来,等之后有点被删掉了之后在加上去。之后询问的时候由于形成了环,所以就可以得到解的情况了。

    代码

    #include<bits/stdc++.h>
    #define M 100005
    using namespace std;
    const int P=1e4+7;
    int inv[M],Ifa[M];
    int n;
    struct node{
    	int k,b;
    	node operator + (const node& res)const{
    		return (node){k*res.k%P,(res.k*b%P+res.b)%P};
    	}
    }val[M],sum[M];
    struct LCT{
    	int ch[M][2],fa[M];
    	void up(int p){
    		sum[p]=sum[ch[p][0]]+val[p]+sum[ch[p][1]];
    	}
    	void create(int x,node d){
    		ch[x][0]=ch[x][1]=fa[x]=0;
    		val[x]=sum[x]=d;
    	}
    	bool isrt(int x){
    		return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
    	}
    	void rotate(int x){
    		int y=fa[x],z=fa[y],k=ch[y][1]==x;
    		if(!isrt(y))ch[z][ch[z][1]==y]=x;fa[x]=z;
    		ch[y][k]=ch[x][!k];fa[ch[x][!k]]=y;
    		ch[x][!k]=y;fa[y]=x;
    		up(y);up(x);
    	}
    	void splay(int x){
    		while(!isrt(x)){
    			int y=fa[x],z=fa[y];
    			if(!isrt(y))
    				(ch[y][1]==x^ch[z][1]==y)?rotate(x):rotate(y);
    			rotate(x);
    		}
    	}
    	void access(int x){
    		for(int y=0;x;y=x,x=fa[x])
    			splay(x),ch[x][1]=y,up(x);
    	}
    	int findrt(int x){
    		access(x);splay(x);
    		while(ch[x][0])x=ch[x][0];
    		splay(x);return x;
    	}
    	bool link(int x,int y){
    		splay(x);
    		if(findrt(y)==x)return 0;
    		fa[x]=y;
    		return 1;
    	}
    	bool cut(int x){
    		access(x),splay(x);
    		if(!ch[x][0])return 0;
    		fa[ch[x][0]]=0;ch[x][0]=0;
    		up(x);
    		return 1;
    	}
    	void update(int x,node d){
    		val[x]=sum[x]=d;
    		up(x);
    		splay(x);
    	}
    	node query(int x){
    		access(x),splay(x);
    		return sum[x];
    	}
    	void Link(int x,int y){
    		if(!link(x,y))Ifa[x]=y;
    	}
    	void Cut(int x){
    		int y=findrt(x);
    		if(!cut(x)){Ifa[x]=0;return;}
    		if(link(y,Ifa[y]))Ifa[y]=0;
    	}
    	int solve(int x){
    		int y=findrt(x),z=Ifa[y];
    		node f=query(z);
    		if(f.k==1)return f.b==0?-2:-1;
    		int vl=f.b*inv[(P+1-f.k)%P]%P;
    		f=query(x);
    		return (f.k*vl+f.b)%P;
    	}
    }Tr;
    int main(){
    	inv[0]=inv[1]=1;
    	for(int i=2;i<=P-1;i++)inv[i]=(P-P/i)*inv[P%i]%P;
    	scanf("%d",&n);
    	for(int i=0;i<=n;i++)Tr.create(i,(node){1,0});
    	for(int i=1;i<=n;i++){
    		int k,p,b;
    		scanf("%d%d%d",&k,&p,&b);
    		Tr.update(i,(node){k,b});
    		Tr.Link(i,p);
    	}
    	int q;
    	scanf("%d",&q);
    	while(q--){
    		char op[5];int a,k,p,b;
    		scanf("%s",op);
    		if(op[0]=='A'){
    			scanf("%d",&a);
    			printf("%d
    ",Tr.solve(a));
    		}
    		else {
    			scanf("%d%d%d%d",&a,&k,&p,&b);
    			Tr.update(a,(node){k,b});
    			Tr.Cut(a);
    			Tr.Link(a,p);
    		}
    	}
    	return 0;
    }
    

    1. [BZOJ 2759 一个动态树好题(动态树)] ↩︎

  • 相关阅读:
    第十七章 Mnesia: Erlang数据库
    第十六章 OTP概述
    第十五章 ETS和DETS:大数据的存储机制
    第十四章 套接字编程
    第十三章 对文件编程
    nginx启动、关闭、重启及常用的命令
    《山海经》异兽75种,附图
    Spring中Configuration的理解
    Spring Boot学习一之Spring Beans和依赖注入
    Spring Boot学习一之配置类及自动配置
  • 原文地址:https://www.cnblogs.com/zryabc/p/10701390.html
Copyright © 2011-2022 走看看