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

    题如其名啊
    昨天晚上写了一发忘保存 只好今天又码一遍了

    将题目中怕(p[i])看做(i)(father) 可以发现每个联通块都是一个基环树 我们对每个基环删掉环上一条边 就可以得到一个森林了 可以用(LCT)维护

    这时我们思考如何求解 对于一个环 拆掉边((u,fa[u]))得到一条链(()下令(v=fa[u]))我们通过关系是从链头(u)向下递推 在(v)点可以得到 (x_v=k_1x_u+b_1) 由删掉的((u,v))边可得关系式 (x_u=k_2x_v+b_2) 带入(x_u)即可解得(x_v) 由于u是链头 所以也是联通块所在树的根 那么树上每个节点都可以从u递推得到形如(x_i=k_ix_v+b_i)的式子 带入(x_v)即可

    实现时的难点在于基环上删除边的操作((u,v)同上()) 可以对于(u)记录$sfa[u]=v $ 每次修改(x)父亲为(y)时 通过求出(sfa)具体讨论(x)在环上还是环外 与(y)连边后构成环还是维持树结构 分类讨论并维护 具体的可以看代码的修改操作

    #include<bits/stdc++.h>
    using namespace std;
    #define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
    #define pa pair<int,int>
    #define mod 10007
    #define ll long long
    #define mk make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define cl(x) memset(x,0,sizeof x)
    #ifdef Devil_Gary
    #define bug(x) cout<<(#x)<<" "<<(x)<<endl
    #define debug(...) fprintf(stderr, __VA_ARGS__)
    #else
    #define bug(x)
    #define debug(...)
    #endif
    const int INF = 0x7fffffff;
    const int N=3e4+5;
    /*
    char *TT,*mo,but[(1<<15)+2];
    #define getchar() ((TT==mo&&(mo=(TT=but)+fread(but,1,1<<15,stdin),TT==mo))?-1:*TT++)//*/
    inline int read(){
        int x=0,rev=0,ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')rev=1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return rev?-x:x;
    }
    struct data{
    	int k,b;
        data(){k=1,b=0;}
        data(int k,int b):k(k),b(b){}
    	int calc(int x){return (k*x+b)%mod;} 
    	data operator +(const data&a) {return data(k*a.k%mod,(b*a.k%mod+a.b)%mod);} 
    };
    int n;
    char s[15];
    void exgcd(int a,int b,int&x,int&y){
    	if(!b) x=1,y=0;
    	else exgcd(b,a%b,y,x),y-=a/b*x;
    }
    #define isroot(x) (c[fa[x]][0]!=x&&c[fa[x]][1]!=x) 
    struct LinkCutTree{
    	int c[N][2],fa[N],sfa[N];
    	data val[N],sum[N];
    	bool vis[N],ins[N];
    	void dfs(int x){
    		ins[x]=vis[x]=1;
    		int y=fa[x];
    		if(ins[y]) fa[x]=0,sfa[x]=y;
    		if(!vis[y]) dfs(y);
    		ins[x]=0;
    	}
    	void update(int x){
    		sum[x]=sum[c[x][0]]+val[x]+sum[c[x][1]];
    	}
    	void init(){
    		for(int i=1,k,b;i<=n;i++) k=read(),fa[i]=read(),b=read(),val[i]=sum[i]=data(k,b);
    		for(int i=1;i<=n;i++) if(!vis[i]) dfs(i); 
    	}
    	void rotate(int x){
    		int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1;
    		if(!isroot(y)) c[z][c[z][1]==y]=x;
    		fa[x]=z,fa[y]=x,fa[c[x][r]]=y;
    		c[y][l]=c[x][r],c[x][r]=y;
    		update(y),update(x);
    	}
    	void splay(int x){
    		while(!isroot(x)){
    			int y=fa[x],z=fa[y];
    			if(!isroot(y)) (c[z][0]==y^c[y][0]==x)?rotate(x):rotate(y);
    			rotate(x);
    		}
    	}
    	void access(int x){
    		for(int t=0;x;c[x][1]=t,update(x),t=x,x=fa[x]) splay(x);
    	}
    	int find(int x){
    		access(x),splay(x);
    		while(c[x][0]) x=c[x][0];
    		splay(x);
    		return x;
    	}
    	int Query(int x){
    		access(x),splay(x);
    		data v1=sum[x];
    		int rt=find(x),rtf=sfa[rt];
    		access(rtf),splay(rtf);
    		data v2=sum[rtf];
    		if(v2.k==1) return v2.b?-1:-2;
    		if(v2.k==0) return v1.calc(v2.b);
    		int xx,y;
    		exgcd(v2.k-1,mod,xx,y);
    		return v1.calc((mod-xx)%mod*v2.b%mod);
    	}
    	void cut(int x){
    		access(x),splay(x),fa[c[x][0]]=0,c[x][0]=0,update(x);
    	}
    	void link(int x,int y){
    		access(x),splay(x),fa[x]=y;
    	}
    	bool judge(int x,int rt){
    		int rtf=sfa[rt];
    		if(x==rtf) return 1;
    		access(rtf),splay(rtf),splay(x);
    		return !isroot(rtf);
    	}
    	void modify(int x,int y,int k,int b){
    		access(x),splay(x),val[x]=data(k,b),update(x);
    		int rt=find(x);
    		if(x==rt){
    			int rtf=find(y);
    			if(rtf==rt) sfa[x]=y;
    			else sfa[x]=0,link(x,y);
    		}
    		else{
    			if(judge(x,rt)) cut(x),link(rt,sfa[rt]),sfa[rt]=0;
    			else cut(x);
    			int rtf=find(y);
    			if(rtf==x) sfa[x]=y;
    			else link(x,y);
    		}
    	}
    }lct;
    int main(){
    #ifdef Devil_Gary
    	freopen("in.txt","r",stdin);
    #endif
    	n=read(),lct.init();
    	for(int Q=read(),k,f,b,x;Q;Q--){
    		scanf("%s",s),x=read();
    		if(s[0]=='A') printf("%d
    ",lct.Query(x));
    		else k=read(),f=read(),b=read(),lct.modify(x,f,k,b);
    	}
    }
    
  • 相关阅读:
    .NET自带控件 ································
    FCKeditor 2.2 + Asp.Net 设置
    . Net 2.0 实现动态切换首页图片···················
    按月统计的问题,即数据中没有该月的数据,该月的数据显示为0
    Active Directory如何用C#进行增加、删除、修改、查询用户与组织单位!
    GridView 的排序 !!
    利用GridView显示主细表并一次编辑明细表所有数据的例子 !!【转自孟子e章】
    [翻译]使用ASP.NET2.0的ReportViewer查看RDLC报表 !!!
    opengl 教程(20) 点光源
    每个程序员都应该了解的内存知识(1)
  • 原文地址:https://www.cnblogs.com/devil-gary/p/9185207.html
Copyright © 2011-2022 走看看