zoukankan      html  css  js  c++  java
  • 【BZOJ2759】—一个动态树好题(LCT+Exgcd)

    传送门


    考虑说把xxp[x]p[x]连边
    那么显然最后会整个图形成一个基环森林

    考虑对于一个环
    任选一条边(u,v)(u,v)断开
    uu设为根,并且记录一个special father,spf[u]=vspecial father,spf[u]=v

    对于每次询问uu,我们先找到uu的根rtrt
    access(spf[rt])access(spf[rt])
    就可以用exgcdexgcd解出rtrt的值
    然后access(u)access(u)
    带入就可以得到a[u]a[u]

    修改的时候要判一下spf[rt]spf[rt]的位置
    如果在u,rtu,rt之间就不用管
    否则就把rtrtspf[rt]spf[rt]连起来

    #include<bits/stdc++.h>
    using namespace std;
    const int RLEN=1<<20|1;
    inline char gc(){
    	static char ibuf[RLEN],*ib,*ob;
    	(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    	return (ob==ib)?EOF:*ib++;
    }
    #define gc getchar
    inline int read(){
    	char ch=gc();
    	int res=0,f=1;
    	while(!isdigit(ch))f^=ch=='-',ch=gc();
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    	return f?res:-res;
    }
    #define ll long long
    #define re register
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    #define cs const
    const int mod=10007;
    inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
    inline void Add(int &a,int b){a=add(a,b);}
    inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
    inline void Dec(int &a,int b){a=dec(a,b);}
    inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
    inline void Mul(int &a,int b){a=mul(a,b);}
    inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
    inline void chemx(int &a,int b){a<b?a=b:0;}
    inline void chemn(int &a,int b){a>b?a=b:0;}
    struct node{
    	int k,b;
    	node(int _k=1,int _b=0):k(_k),b(_b){}
    	friend inline node operator +(cs node &a,cs node &b){
    		return node(a.k*b.k%mod,(a.b*b.k+b.b)%mod);
    	}
    };
    cs int N=300005;
    inline void exgcd(int &x,int &y,int a,int b){
    	if(b==0){x=1,y=0;return;}
    	exgcd(y,x,b,a%b),y-=(a/b)*x;
    }
    inline int inv(int a){
    	int x,y;
    	exgcd(x,y,(a+mod)%mod,mod);
    	return (x+mod)%mod;
    }
    namespace Lct{
    	int fa[N],son[N][2],sf[N],rev[N];
    	node val[N],s[N];
    	#define lc(u) son[u][0]
    	#define rc(u) son[u][1]
    	inline void initnode(int u,int k,int b){
    		s[u]=val[u]=node(k,b);
    	}
    	inline bool isrc(int u){
    		return rc(fa[u])==u;
    	}
    	inline bool isrt(int u){
    		return lc(fa[u])!=u&&rc(fa[u])!=u;
    	}
    	inline void pushup(int u){
    		s[u]=s[lc(u)]+val[u]+s[rc(u)];
    	}
    	inline void pushdown(int u){
    		if(!rev[u])return;
    		if(lc(u))rev[lc(u)]^=1;
    		if(rc(u))rev[rc(u)]^=1;
    		swap(lc(u),rc(u));
    		rev[u]=0;
    	}
    	inline void rotate(int v){
    		int u=fa[v],z=fa[u];
    		int t=isrc(v);
    		fa[v]=z;
    		if(!isrt(u))son[z][isrc(u)]=v;
    		son[u][t]=son[v][t^1];
    		fa[son[v][t^1]]=u;
    		fa[u]=v,son[v][t^1]=u;
    		pushup(u),pushup(v);
    	}
    	int stk[N],top;
    	inline void splay(int u){
    		stk[top=1]=u;
    		for(int v=u;!isrt(v);v=fa[v])stk[++top]=fa[v];
    		for(int i=top;i;i--)pushdown(stk[i]);
    		while(!isrt(u)){
    			if(!isrt(fa[u]))
    			isrc(u)==isrc(fa[u])?rotate(fa[u]):rotate(u);
    			rotate(u);
    		}
    	}
    	inline void access(int u){
    		for(int v=0;u;v=u,u=fa[u]){
    			splay(u),rc(u)=v;
    			if(v)fa[v]=u;
    			pushup(u);
    		}
    	}
    	inline void makert(int u){
    		access(u),splay(u),rev[u]^=1;
    	}
    	inline void link(int u,int v){
    		makert(u),splay(v),fa[u]=v;
    	}
    	inline void cut(int u,int v){
    		makert(u),access(v),splay(v);
    		fa[u]=lc(v)=0,pushup(v);
    	}
    	inline void split(int u,int v){
    		makert(u),access(v),splay(v);
    	}
    	inline int findrt(int u){
    		access(u),splay(u);
    		while(pushdown(u),lc(u))u=lc(u);
    		splay(u);return u;
    	}
    	inline int query(int u){
    		int pp=findrt(u);
    		access(sf[pp]),splay(sf[pp]);
    		int k=s[sf[pp]].k,b=s[sf[pp]].b;
    		if(k==1&&b)return -1;
    		if(k==1&&!b)return -2;
    		int v=(mod-b)*inv(k-1)%mod;
    		access(u),splay(u);
    		return (s[u].k*v+s[u].b)%mod;
    	}
    	inline void update(int u,int k,int p,int b){
    		access(u),splay(u),val[u]=node(k,b);
    		pushup(u);
    		int rt=findrt(u);
    		if(rt==u){sf[u]=0;}
    		else{
    			access(u),splay(u);
    			fa[lc(u)]=0,lc(u)=0;
    			pushup(u);
    			if(findrt(sf[rt])!=rt){
    				link(rt,sf[rt]),sf[rt]=0;
    			}
    		}
    		if(findrt(p)==u)sf[u]=p;
    		else link(u,p);
    	}
    }
    int n,m,p[N],vis[N],tot;
    void dfs(int u){
    	vis[u]=tot;
    	if(vis[p[u]]!=tot){Lct::fa[u]=p[u];if(!vis[p[u]])dfs(p[u]);}
    	else Lct::sf[u]=p[u];
    }
    char op[5];
    signed main(){
    	n=read();
    	for(int i=1;i<=n;i++){
    		int k=read();p[i]=read();int b=read();
    		Lct::initnode(i,k,b);
    	}
    	for(int i=1;i<=n;i++)if(!vis[i])++tot,dfs(i);
    	m=read();
    	while(m--){
    		scanf("%s",op+1);
    		if(op[1]=='A'){
    			int x=read();
    			cout<<Lct::query(x)<<'
    ';
    		}
    		else{
    			int x=read(),k=read(),pp=read(),b=read();
    			Lct::update(x,k,pp,b);
    		}
    	}
    }
    
  • 相关阅读:
    学习笔记
    .net $&替换正则查找到的内容
    sql 常用日期函数
    2010学习计划
    优化存储过程
    sql server 标量值函数
    job88数据库操作
    .net 调用有返回值的存储过程
    GridView 18种操作
    SQLite的局限性
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328606.html
Copyright © 2011-2022 走看看