LCT

学习博客:https://www.cnblogs.com/flashhu/p/8324551.html

LCT 更适合于维护链的信息,子树信息也可以维护,但比较麻烦

LCT 通过对辅助树的操作来实现连边,删边,以及各种信息的维护,认父不认子。

注意区分实边和虚边,splay中维护的是实边,通过对实边的变换,来得到具体链的信息。

 

P3690 【模板】Link Cut Tree (动态树)

直接粘代码

#include<bits/stdc++.h>
#define N 110000
using namespace std;
int n,m,tr[N][2],s[N],v[N],f[N],r[N];
int noroot(int x){//判断节点是否为一个Splay的根(与普通Splay的区别1)
	return tr[f[x]][0]==x||tr[f[x]][1]==x;
}
void pushup(int x){
	s[x]=s[tr[x][0]]^s[tr[x][1]]^v[x];
}
void pushr(int x){
	swap(tr[x][0],tr[x][1]);
	r[x]^=1;
}
void pushdown(int x){
	if(r[x]){
		if(tr[x][0])pushr(tr[x][0]);
		if(tr[x][1])pushr(tr[x][1]);
		r[x]=0;
	}
}
void pushall(int x){
	if(noroot(x))pushall(f[x]);
	pushdown(x);
}
void rotate(int x){
	int y=f[x],z=f[y],k=(tr[y][1]==x),w=tr[x][!k];
	if(noroot(y)){
		tr[z][tr[z][1]==y]=x;
	}
	tr[x][!k]=y;tr[y][k]=w;
	if(w)f[w]=y;
	f[y]=x;f[x]=z;
	pushup(y);
}
void splay(int x){
	int y=x,z=0;
	pushall(x);
	while(noroot(x)){
		y=f[x];z=f[y];
		if(noroot(y)) 
			rotate((tr[y][0]==x)^(tr[z][0]==y)?x:y);
		rotate(x);
	}
	pushup(x);
}

void access(int x){
	for(int y=0;x;y=x,x=f[x]){
		splay(x);tr[x][1]=y;pushup(x);
	}
}

void makeroot(int x){
	access(x);splay(x);
	pushr(x);
} 


void split(int x,int y){
	makeroot(x);
	access(y);splay(y);
}
int findroot(int x){
	access(x);splay(x);
	while(tr[x][0])pushdown(x),x=tr[x][0];
	splay(x);
	return x; 
}
void cut(int x,int y){
	makeroot(x);
	if(findroot(y)==x&&f[y]==x&&!tr[y][0]){
		tr[x][1]=0;f[y]=0;
		pushup(x);
	}
}
void link(int x,int y){
	makeroot(x);
	if(findroot(y)!=x)f[x]=y;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&v[i]);
	int op,x,y;
	while(m--){
		scanf("%d%d%d",&op,&x,&y);
		if(op==0){
			split(x,y);printf("%d\n",s[y]);
		}
		else if(op==1)link(x,y);
		else if(op==2)cut(x,y);
		else {
			splay(x);v[x]=y;
		}
	}
	return 0;
}

P3203 [HNOI2010]弹飞绵羊

i向i+k[i]连边,建树,维护森林,答案是链上的节点数

P1501 [国家集训队]Tree II

多了一个区间修改,注意pushup时要把自己本身的值算上,注意先乘后加

#include<bits/stdc++.h>
#define N 110000
#define LL long long
using namespace std;
int n,m,tr[N][2],f[N],r[N];
LL s[N],v[N],add[N],mul[N],sz[N];
const int md=51061;
int noroot(int x){
	return tr[f[x]][0]==x||tr[f[x]][1]==x;
}
void pushup(int x){
	sz[x]=sz[tr[x][0]]+sz[tr[x][1]]+1;
	s[x]=(s[tr[x][0]]+s[tr[x][1]]+v[x]);
}
void pushr(int x){
	swap(tr[x][0],tr[x][1]);
	r[x]^=1;
}
void pushdown(int x){
	int lc=tr[x][0],rc=tr[x][1];
	if(mul[x]!=1){
		if(lc){
			mul[lc]=mul[lc]*mul[x]%md;	
			add[lc]=add[lc]*mul[x]%md;
			s[lc]=(s[lc]*mul[x])%md;
			v[lc]=v[lc]*mul[x]%md;
		}
		if(rc){
			mul[rc]=mul[rc]*mul[x]%md;
			add[rc]=add[rc]*mul[x]%md;
			s[rc]=s[rc]*mul[x]%md;
			v[rc]=v[rc]*mul[x]%md;
		}
		mul[x]=1;
	}
	if(add[x]){
		if(lc){
			add[lc]=(add[lc]+add[x])%md;
			s[lc]=(s[lc]+add[x]*sz[lc]%md)%md;
			v[lc]=(v[lc]+add[x])%md;
		}
		if(rc){
			add[rc]=(add[rc]+add[x])%md;
			s[rc]=(s[rc]+add[x]*sz[rc]%md)%md;
			v[rc]=(v[rc]+add[x])%md;
		}
		add[x]=0;
	}
	if(r[x]){
		if(lc)pushr(lc);
		if(rc)pushr(rc);
		r[x]=0;
	}
}
void pushall(int x){
	if(noroot(x))pushall(f[x]);
	pushdown(x);
}
void rotate(int x){
	int y=f[x],z=f[y],k=(tr[y][1]==x),w=tr[x][!k];
	if(noroot(y))tr[z][tr[z][1]==y]=x;
	tr[x][!k]=y;tr[y][k]=w;
	if(w)f[w]=y;
	f[y]=x;f[x]=z;
	pushup(y);
}
void splay(int x){
	int y=x,z=0;
	pushall(x);
	while(noroot(x)){
		y=f[x];z=f[y];
		if(noroot(y)) 
			rotate((tr[y][0]==x)^(tr[z][0]==y)?x:y);
		rotate(x);
	}
	pushup(x);
}

void access(int x){
	for(int y=0;x;y=x,x=f[x]){
		splay(x);tr[x][1]=y;pushup(x);
	}
}

void makeroot(int x){
	access(x);splay(x);
	pushr(x);
} 
void split(int x,int y){
	makeroot(x);
	access(y);

	splay(y);
}
int findroot(int x){
	access(x);splay(x);
	while(tr[x][0])pushdown(x),x=tr[x][0];
	splay(x);
	return x; 
}
void cut(int x,int y){
	makeroot(x);
	if(findroot(y)==x&&f[y]==x&&!tr[y][0]){
		tr[x][1]=0;f[y]=0;
		pushup(x);
	}
}
void link(int x,int y){
	makeroot(x);
	if(findroot(y)!=x)f[x]=y;
}
int main(){
	int q;
	scanf("%d%d",&n,&q);
	int x,y;
	for(int i=1;i<=n;i++){
		v[i]=1;mul[i]=1;sz[i]=1;
	}
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		link(x,y);
	}
	int u1,v1,u2,v2;
	LL c;
	char op[100];
	while(q--){
		scanf("%s",op);
		if(op[0]=='+'){
			scanf("%d%d%lld",&u1,&v1,&c);
			split(u1,v1);
			add[v1]=(add[v1]+c)%md;s[v1]=(s[v1]+sz[v1]*c%md)%md;
			v[v1]=(v[v1]+c)%md;
		}
		else if(op[0]=='-'){
			scanf("%d%d%d%d",&u1,&v1,&u2,&v2);
			cut(u1,v1);link(u2,v2);
		}
		else if(op[0]=='*'){
			scanf("%d%d%lld",&u1,&v1,&c);
			split(u1,v1);
			add[v1]=(add[v1]*c)%md;
			mul[v1]=mul[v1]*c%md;
			s[v1]=(s[v1]*c)%md;
			v[v1]=(v[v1]*c)%md;
		}
		else if(op[0]=='/'){
			scanf("%d%d",&u1,&v1);
			//cin>>u1>>v1;
			split(u1,v1);
			printf("%lld\n",s[v1]%md);
		}
	}
	return 0;
}

P2147 [SDOI2008]洞穴勘测

对图的连通性判断,通过link与cut可以实现动态加边与删边

P2542 [AHOI2005] 航线规划

如果图中出现环,则环中的边对答案没有贡献,贡献变为就好了,对于每一条边都新建一个点,如边(x,y),新建点cnt,link(x,cnt);link(y,cnt),这样就可以维护边的信息了

对于询问(x,y)答案就变成了x到y的链上有效边的个数(无效的被置成0了)

#include<bits/stdc++.h>
#define N 310000
using namespace std;
int n,m,tr[N][2],s[N],v[N],f[N],r[N],add[N];
set<int>se[100100];
struct nd{
	int op,x,y,ans;
}a[N],q[N];
int noroot(int x){
	return tr[f[x]][0]==x||tr[f[x]][1]==x;
}
void pushup(int x){
	s[x]=s[tr[x][0]]+s[tr[x][1]]+v[x];
	//sz[x]=sz[tr[x][0]]+sz[tr[x][1]]+1;
}
void pushr(int x){
	swap(tr[x][0],tr[x][1]);
	r[x]^=1;
}
void pushdown(int x){
	if(r[x]){
		if(tr[x][0])pushr(tr[x][0]);
		if(tr[x][1])pushr(tr[x][1]);
		r[x]=0;
	}
	if(add[x]!=-1){
		if(tr[x][0]){
			add[tr[x][0]]=add[x];
			s[tr[x][0]]=0;
			v[tr[x][0]]=0;
		}
		if(tr[x][1]){
			add[tr[x][1]]=add[x];
			s[tr[x][1]]=0;
			v[tr[x][1]]=0;
		}
		add[x]=-1;
	}
}
void pushall(int x){
	if(noroot(x))pushall(f[x]);
	pushdown(x);
}
void rotate(int x){
	int y=f[x],z=f[y],k=(tr[y][1]==x),w=tr[x][!k];
	if(noroot(y))tr[z][tr[z][1]==y]=x;
	tr[x][!k]=y;tr[y][k]=w;
	if(w)f[w]=y;
	f[y]=x;f[x]=z;
	pushup(y);
}
void splay(int x){
	pushall(x);
	int y,z=0;
	while(noroot(x)){
		y=f[x];z=f[y];
		if(noroot(y))rotate((tr[y][0]==x)^(tr[z][0]==y)?x:y);
		rotate(x);
	}
	pushup(x);
}
void access(int x){
	for(int y=0;x;y=x,x=f[x]){
		splay(x);tr[x][1]=y;pushup(x);
	}
}
void makeroot(int x){
	access(x);splay(x);
	pushr(x);
}
void split(int x,int y){
	makeroot(x);access(y);
	splay(y);
}
int findroot(int x){
	access(x);splay(x);
	while(tr[x][0])pushdown(x),x=tr[x][0];
	splay(x);
	return x;
}
int link(int x,int y){
	makeroot(x);
	if(findroot(y)!=x){
		f[x]=y;return 1;
	}
}
int pd(int x,int y){
	makeroot(x);
	return findroot(y)==x;
}
int main(){
	scanf("%d%d",&n,&m);
	memset(add,-1,sizeof(add));
	for(int i=1;i<=m;i++){
		scanf("%d%d",&a[i].x,&a[i].y);
	}
	int qt=0;
	while(1){
		scanf("%d",&q[++qt].op);
		int i=qt;
		if(q[i].op==-1)break;
		else if(q[i].op==0){
			scanf("%d%d",&q[i].x,&q[i].y);
			se[q[i].x].insert(q[i].y);
			se[q[i].y].insert(q[i].x);
		}
		else {
			scanf("%d%d",&q[i].x,&q[i].y);
		}
	}
	qt--;
	int cnt=n;
	for(int i=1;i<=m;i++){
		if(!se[a[i].x].count(a[i].y)){
			if(!pd(a[i].x,a[i].y)){
				++cnt;v[cnt]=s[cnt]=1;
				link(a[i].x,cnt);
				link(a[i].y,cnt);
			}
			else{
				split(a[i].x,a[i].y);
				add[a[i].y]=0;v[a[i].y]=s[a[i].y]=0;
			}
		}
	}
	for(int i=qt;i>=1;i--){
		if(q[i].op==1){
			split(q[i].x,q[i].y);
			q[i].ans=s[q[i].y];
		}
		else{
			if(!pd(q[i].x,q[i].y)){
				cnt++;v[cnt]=s[cnt]=1;
				link(q[i].x,cnt);
				link(q[i].y,cnt);
			}
			else{
				split(q[i].x,q[i].y);
				add[q[i].y]=0;v[q[i].y]=s[q[i].y]=0;
			}
		}
	}
	for(int i=1;i<=qt;i++)
	if(q[i].op==1)printf("%d\n",q[i].ans);
	return 0;
}

P4172 [WC2006]水管局长

动态维护最小生成树,当出现环时,把环上最大边替掉

#include<bits/stdc++.h>
#define N 210000
using namespace std;
int n,m,tr[N][2],v[N],f[N],r[N],c[N][2],dis[1010][1010];
struct nd{
	int val,id,x,y,op,ans,z;
}mx[N],a[N],q[N];
set<int>se[N];
int noroot(int x){//判断节点是否为一个Splay的根(与普通Splay的区别1)
	return tr[f[x]][0]==x||tr[f[x]][1]==x;
}
void pushup(int x){
	nd t;
	t.val=v[x];t.id=x;
	if(tr[x][0]&&mx[tr[x][0]].val>t.val)t=mx[tr[x][0]];
	if(tr[x][1]&&mx[tr[x][1]].val>t.val)t=mx[tr[x][1]];
	mx[x]=t;
}
void pushr(int x){
	swap(tr[x][0],tr[x][1]);
	r[x]^=1;
}
void pushdown(int x){
	if(r[x]){
		if(tr[x][0])pushr(tr[x][0]);
		if(tr[x][1])pushr(tr[x][1]);
		r[x]=0;
	}
}
void pushall(int x){
	if(noroot(x))pushall(f[x]);
	pushdown(x);
}
void rotate(int x){
	int y=f[x],z=f[y],k=(tr[y][1]==x),w=tr[x][!k];
	if(noroot(y))tr[z][tr[z][1]==y]=x;
	tr[x][!k]=y;tr[y][k]=w;
	if(w)f[w]=y;
	f[y]=x;f[x]=z;
	pushup(y);
}
void splay(int x){
	int y=x,z=0;
	pushall(x);
	while(noroot(x)){
		y=f[x];z=f[y];
		if(noroot(y)) 
			rotate((tr[y][0]==x)^(tr[z][0]==y)?x:y);
		rotate(x);
	}
	pushup(x);
}

void access(int x){
	for(int y=0;x;y=x,x=f[x]){
		splay(x);tr[x][1]=y;pushup(x);
	}
}

void makeroot(int x){
	access(x);splay(x);
	pushr(x);
} 


void split(int x,int y){
	makeroot(x);
	access(y);splay(y);
}
int findroot(int x){
	access(x);splay(x);
	while(tr[x][0])pushdown(x),x=tr[x][0];
	splay(x);
	return x; 
}
void cut(int x,int y){
	makeroot(x);
	if(findroot(y)==x&&f[y]==x&&!tr[y][0]){
		tr[x][1]=0;f[y]=0;
		pushup(x);
	}
}
void link(int x,int y){
	makeroot(x);
	if(findroot(y)!=x)f[x]=y;
}
nd getmx(int x,int y){
	split(x,y);
	return mx[y];
}
int pd(int x,int y){
	makeroot(x);
	return findroot(y)==x;
}
int main(){
	int qt;
	scanf("%d%d%d",&n,&m,&qt);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
		dis[a[i].x][a[i].y]=a[i].z;
		dis[a[i].y][a[i].x]=a[i].z;
	}
	for(int i=1;i<=qt;i++){
		scanf("%d%d%d",&q[i].op,&q[i].x,&q[i].y);
		if(q[i].op==2){
			se[q[i].x].insert(q[i].y);
			se[q[i].y].insert(q[i].x);
		}
	}
	int cnt=n;
	for(int i=1;i<=m;i++){
		if(!se[a[i].x].count(a[i].y)){
			if(!pd(a[i].x,a[i].y)){
				cnt++;
				c[cnt][0]=a[i].x;c[cnt][1]=a[i].y;
				v[cnt]=mx[cnt].val=a[i].z;
				mx[cnt].id=cnt;
				link(a[i].x,cnt);link(a[i].y,cnt);
			}
			else{
				nd t=getmx(a[i].x,a[i].y);
				if(t.val>a[i].z){
				//	mx[t.id].val=0;v[t.id]=0;
					cut(t.id,c[t.id][0]);
					cut(t.id,c[t.id][1]);
					++cnt;c[cnt][0]=a[i].x;
					c[cnt][1]=a[i].y;
					v[cnt]=mx[cnt].val=a[i].z;
					mx[cnt].id=cnt;
					link(a[i].x,cnt);link(a[i].y,cnt);
				}
			}
		}
	}
	for(int i=qt;i>=1;i--){
		if(q[i].op==1){
			split(q[i].x,q[i].y);
			q[i].ans=mx[q[i].y].val;
			//cout<<mx[q[i].y].id<<" "<<i<<endl;
		}
		else{
			if(!pd(q[i].x,q[i].y)){
				++cnt;
				c[cnt][0]=q[i].x;c[cnt][1]=q[i].y;
				v[cnt]=mx[cnt].val=dis[q[i].x][q[i].y];
				mx[cnt].id=cnt;
				link(q[i].x,cnt);
				link(q[i].y,cnt);
			}
			else {
				nd t=getmx(q[i].x,q[i].y);
				if(t.val>dis[q[i].x][q[i].y]){
				//	v[t.id]=mx[t.id].val=0;
				//	cout<<c[t.id][0]<<" "<<c[t.id][1]<<endl;
					cut(t.id,c[t.id][0]);
					cut(t.id,c[t.id][1]);
					++cnt;
					//cout<<pd(t.id,c[t.id][0])<<"L"<<endl;
					c[cnt][0]=q[i].x;c[cnt][1]=q[i].y;
					v[cnt]=mx[cnt].val=dis[q[i].x][q[i].y];
					mx[cnt].id=cnt;
					link(q[i].x,cnt);
					link(q[i].y,cnt);
				}
			}
		}
	}
	for(int i=1;i<=qt;i++)
	if(q[i].op==1)printf("%d\n",q[i].ans);
	return 0;
}

P4180 [BJWC2010]严格次小生成树

次小生成树与最小生成树只差一条边,所以建好最下生成树以后,枚举剩下的边,求出环中的最大与次大值(有可能枚举的边与最大相等,这就要替代次大)

更新答案

P4234 最小差值生成树

按照边权先排序,进行建树,如果出现环则替代掉环中最小值,因为边权权是递增的,替代掉最小的肯定是最优的,如果形成树则更新答案

这个过程也可以理解为枚举每一条边当做最小值所构成的生成树

 

P2387 [NOI2014] 魔法森林

将a从小到大排序,然后维护b的最小生成树,因为a是递增的,所以b要尽量小,出现环时要替代掉环中最大值

将边按照边权A排序

然后不断的加边,如果一条边连接了两个联通块,那么这条路径是必需的。

这个时候我们保证了边权A单调递增,我们用LCT维护图中的边权B

然后对于一条路径,如果其沟通了两个已经联通的联通块,我们可以这样考虑:

当前路径的A比之前存在的任意路径的A都大,如果其B比这环上边B的最大值还要大,那么加入这条边只会让答案变得更不优。

如果当前路径的B比环上最大的B要小,那么加入这条路径后,显然有:

(1)假如当前1-n未联通,那么对于后续的边,若其加入后可以使1-n联通,不难想到:其A显然仍然大于当前边,所以我们需要最小化链上的B,也就是断掉环上最大B的边,然后加入这条边

(2)假如当前1-n已经联通,我们实际上已经求得了最大 A 比此边小的时候的答案,我们可以先加入此边,求出最大 A 稍微大一点的答案,取min,然后类似(1)的分析,可以发现这条边加入后会使得后续边算得的答案更优。

当然前提是这条边的B大于环上最大B

注意是判断1与n路径上的最大值,而不是所有节点的最大值

P4219 [BJOI2014]大融合

维护子树信息,注意算答案的时候节点要是在同一个splay 中的,

#include<bits/stdc++.h>
#define N 210000
#define LL long long
using namespace std;
int n,m,tr[N][2],v[N],f[N],r[N];
LL s[N],s2[N];
int noroot(int x){
	return tr[f[x]][0]==x||tr[f[x]][1]==x;
}
void pushup(int x){
	s[x]=s[tr[x][0]]+s[tr[x][1]]+1+s2[x];
}
void pushr(int x){
	swap(tr[x][0],tr[x][1]);
	r[x]^=1;
}
void pushdown(int x){
	if(r[x]){
		if(tr[x][0])pushr(tr[x][0]);
		if(tr[x][1])pushr(tr[x][1]);
		r[x]=0;
	}
}
/*void pushall(int x){
	if(noroot(x))pushall(f[x]);
	pushdown(x);
}
/*void rotate(int x){
	int y=f[x],z=f[y],k=(tr[y][1]==x),w=tr[x][!k];
	if(noroot(y))tr[z][tr[z][1]==y]=x;
	tr[x][!k]=y;tr[y][k]=w;
	if(w)f[w]=y;
	f[y]=x;f[x]=z;
	pushup(y);
}
void splay(int x){
	pushall(x);
	int y,z;
	while(noroot(x)){
		y=f[x];z=f[y];
		if(noroot(y))rotate((tr[y][0]==x)^(tr[z][0]==y)?x:y);
		rotate(x);
	}
	pushup(x);
}
void access(int x){
	for(int y=0;x;y=x,x=f[x]){
		splay(x);s2[x]+=s[tr[x][1]]-s[y];
		tr[x][1]=y;pushup(x);
	}
}
void makeroot(int x){
	access(x);splay(x);
	pushr(x);
}
int findroot(int x){
	access(x);splay(x);
	while(tr[x][0])pushdown(x),x=tr[x][0];
	splay(x);
	return x; 
}
void link(int x,int y){
	makeroot(x);
	if(findroot(y)!=x){
		f[x]=y;
		s2[y]+=s[x];
	}	
}
void cut(int x,int y){
	makeroot(x);
	if(findroot(y)==x&&f[y]==x&&!tr[y][0]){
		tr[x][1]=0;f[y]=0;
		pushup(x);
	}
}*/
void dfs(int x){
	if(tr[x][0])dfs(tr[x][0]);
	cout<<x<<endl;
	if(tr[x][1])dfs(tr[x][1]);
}
void pushall(int x){
	if(noroot(x))pushall(f[x]);
	pushdown(x);
}
void rotate(int x){
	int y=f[x],z=f[y],k=(tr[y][1]==x),w=tr[x][!k];
	if(noroot(y))tr[z][tr[z][1]==y]=x;
	tr[x][!k]=y;tr[y][k]=w;
	if(w)f[w]=y;
	f[y]=x;f[x]=z;
	pushup(y);
}
void splay(int x){
	pushall(x);
	int y,z;
	while(noroot(x)){
		y=f[x];z=f[y];
		if(noroot(y))rotate((tr[y][0]==x)^(tr[z][0]==y)?x:y);
		rotate(x);
	}
	pushup(x);
}
void access(int x){
	for(int y=0;x;y=x,x=f[x]){
		splay(x);s2[x]+=s[tr[x][1]]-s[y];tr[x][1]=y;pushup(x);
	}
}
void makeroot(int x){
	access(x);splay(x);
	pushr(x);
}
void split(int x,int y){
	makeroot(x);
	access(y);splay(y);
}
int findroot(int x){
	access(x);splay(x);
	while(tr[x][0])pushdown(x),x=tr[x][0];
	splay(x);
	return x;
}
void link(int x,int y){
	makeroot(x);
	access(y);splay(y);f[x]=y,s2[y]+=s[x];
	pushup(y);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	v[i]=1;
	LL ans;
	char op[10];
	int x,y;
	for(int i=1;i<=m;i++){
		scanf("%s",op);
		scanf("%d%d",&x,&y);
		if(op[0]=='A')link(x,y);
		else{
			makeroot(x);
			access(y);splay(y);
		
			ans=(LL)(s[y]-s[x])*s[x];
			printf("%lld\n",ans);
		}
	}
	return 0;
}

P4299 首都

数的中心问题,题解在上面学习博客里

 

 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值