Codeforces 图论tag题合集(1)

Codeforce 图论tag题 2021.5

CR#693(div3)————
G. Moving to the Capital (树上DP)

There are n cities in Berland. The city numbered 1 is the capital. Some pairs of cities are connected by a one-way road of length 1.
Before the trip, Polycarp for each city found out the value of di — the shortest distance from the capital (the 1-st city) to the i-th city.
Polycarp begins his journey in the city with number s and, being in the i-th city, chooses one of the following actions:
Travel from the i-th city to the j-th city if there is a road from the i-th city to the j-th and di<dj;
Travel from the i-th city to the j-th city if there is a road from the i-th city to the j-th and di≥dj;
Stop traveling.
Since the government of Berland does not want all people to come to the capital, so Polycarp no more than once can take the second action from the list. in other words, he can perform the second action 0 or 1 time during his journey. Polycarp, on the other hand, wants to be as close to the capital as possible.
For example, if n=6 and the cities are connected, as in the picture above, then Polycarp could have made the following travels (not all possible options):
2→5→1→2→5;
3→6→2;
1→3→6→2→5.
Polycarp wants for each starting city i to find out how close he can get to the capital. More formally: he wants to find the minimal value of dj that Polycarp can get from the city i to the city j according to the rules described above.

题意:给定一个有向图,可以朝远离结点1的方向行走无限次,或者朝靠近1的地方行走一次,求所有点到1的最近距离。
BFS跑出所有点的距离,随后从最远点开始DP,
对于靠近首都的边,用ans[u]=min(dis[v],ans[u])更新
对于远离首都的边,用ans[u]=min(ans[u],ans[v])更新

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define int long long
using namespace std;
const int maxn=2e5+5;
vector<int> R[maxn]={};//存边
vector<int> P[maxn]={};//存储相同dis的节点
int n,m;
int ans[maxn]={};
int dis[maxn]={};
bool vis[maxn]={};
 
signed main(){
	int t;cin>>t;while(t--){
         cin>>n>>m;
		for(int i=1;i<=n;i++){
		ans[i]=maxn;dis[i]=0;vis[i]=0;
			R[i].clear();                    
		}
		while(m--){
			int u,v;cin>>u>>v;
			R[u].push_back(v);
		}
        //BFS求dis
		queue<int>q;                        
		for(auto i:R[1]){
			q.push(i);
			dis[i]=1;vis[i]=1;
			P[1].push_back(i);
		}
		dis[1]=0;vis[1]=1;
		int dismx=1;
		P[0].push_back(1);
		while(!q.empty()){
			int x=q.front();
			q.pop();
			for(auto y:R[x]){
				if(vis[y])continue;
				q.push(y);
				dis[y]=dis[x]+1;
				vis[y]=1;
				dismx=max(dismx,dis[y]);
				P[dis[y]].push_back(y);
				
			}
		}         
		//将所有点的ans初始化为dis(原地不动即为最优解)
		for(int i=1;i<=n;i++)ans[i]=dis[i];
		for(int i=dismx;i>=0;i--){//从远到近DP,i代表当前DP点的dis
			for(auto node:P[i]){
				for(auto y:R[node]){
				/*如果遍历的边所达到的节点离首都更近,则将ans用该点的dis更新(由于此技能只能用一次,
				故使用后所达到的第一个点一定是最优解)*/
					if(dis[y]<=dis[node])ans[node]=min(ans[node],dis[y]);
				/*如果遍历的边所到达的节点离首都远,则用该点的ans进行更新(由于该点离首都更远,故
				访问的时候它一定已经被更新为最优解)*/
					else ans[node]=min(ans[y],ans[node]);
				}
			}
		}
		for(int i=1;i<=n;i++)cout<<ans[i]<<' ';
		cout<<endl;
	}
	return 0;
}

(一开始读错了题意导致一直在反向思考,后来才把DP改为从远到近。)

CGR#14————
G. Phoenix and Odometers(Targan缩点+数论)
In Fire City, there are n intersections and m one-way roads. The i-th road goes from intersection ai to bi and has length li miles.
There are q cars that may only drive along those roads. The i-th car starts at intersection vi and has an odometer that begins at si, increments for each mile driven, and resets to 0 whenever it reaches ti. Phoenix has been tasked to drive cars along some roads (possibly none) and return them to their initial intersection with the odometer showing 0.
For each car, please find if this is possible.
A car may visit the same road or intersection an arbitrary number of times. The odometers don’t stop counting the distance after resetting, so odometers may also be reset an arbitrary number of times.
题意:给定一个有向图加权图,给定q个询问,v,s,t,求从v点开始,能否找到一条复杂回路(不一定是简单路径),让总长度sum+s能被t整除。
由裴蜀定理可知,该连通块能生成的路程长度为所有环总gcd(sum)的倍数,故如果只需判断gcd(sum,t)能否被gcd(s,t)整除即可。(一定可以构造出gcd(s,t)+k*gcd(sum,t)=t)
于是只要跑targan缩点,随后求出每个点所在连通块中存在的所有环路的gcd便可以了。
我们可以在进行targan算法的同时求出每个联通块的gcd,随后每次访问时,简单计算即可。

#include<iostream>
#include<vector>
#include<queue>
#define int long long
using namespace std;
const int maxn=2e5+5;
int n,m;
struct edge{          //这里由于带权,用链式前向星存储
	int to,nxt,w;
}e[maxn]={};
int head[maxn],ecnt;  
void addage(int u,int v,int w){
	edge temp;  
	temp.to=v,temp.nxt=head[u],temp.w=w;
	e[++ecnt]=temp;
	head[u]=ecnt;
}
int G[maxn],///当前点的总gcd
S[maxn];//整个连通块的总gcd
int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);}
int t[maxn],low[maxn],dfn,//targan相关
stk[maxn],top,//手写栈
ins[maxn],//标记节点是否已被弹出
id[maxn],scc;//连通块标记
int dis[maxn];//深度
void dfs(int u){  //targan
	ins[stk[++top]=u]=1,low[u]=t[u]=++dfn;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(!t[v]){//前向边(节点未被访问)
			dis[v]=dis[u]+e[i].w;//更新节点深度
			dfs(v);
			low[u]=min(low[u],low[v]);//更新low
		}
		else if(ins[v]){
			low[u]=min(low[u],t[v]);//更新low
			G[u]=gcd(G[u],dis[u]-dis[v]+e[i].w);//更新u点连通块的gcd
			//每个环均只会经过一条独立的后向边,故可以通过此方法记录所有环的长度
		}
	}
	if(low[u]==t[u]){
		++scc;//连通块标签
		for(int v=-1;v!=u;){
			ins[v=stk[top--]]=0;//弹栈,将u以下的子树全部弹出
			id[v]=scc,S[scc]=gcd(S[scc],G[v]);//合并gcd
		}
	}
}
signed main(){
	std::ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		addage(u,v,w);
	}
	for(int i=1;i<=n;i++){
		if(!t[i])dfs(i);
	}
	int q;cin>>q;
	while(q--){
		int p,s,t;cin>>p>>s>>t;
		s=gcd(s,t);t=gcd(t,S[id[p]]);
		if(s%t==0)cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}
 

F. Phoenix and Earthquake(树上并查集,贪心)
Phoenix’s homeland, the Fire Nation had n cities that were connected by m roads, but the roads were all destroyed by an earthquake. The Fire Nation wishes to repair n−1 of these roads so that all the cities are connected again.
The i-th city has ai tons of asphalt. x tons of asphalt are used up when repairing a road, and to repair a road between i and j, cities i and j must have at least x tons of asphalt between them. In other words, if city i had ai tons of asphalt and city j had aj tons, there would remain ai+aj−x tons after repairing the road between them. Asphalt can be moved between cities if the road between them is already repaired.
Please determine if it is possible to connect all the cities, and if so, output any sequence of roads to repair.

题意:给定带权点的无向图,如果该点权值大于x,可花费x将其与任意邻接点点联通并且共享权值,求最后能否将所有点联通。
首先特判一个总量小于(n-1)*x的情况。随后我们可以贪心将当前权值最大的点与任意一个未连接的点合并。注意,由于总量大于(n-1)*x,故每次连接后一定存在权值大于x的点,故这里并不需要继续贪心。

#include<iostream>
#include<queue>
#include<vector>
using namespace std;
const int maxn=1000000+5;
long long n,m,x;
#define ll long long
ll p[maxn],a[maxn];
vector <vector<pair<ll,ll>>> v;
ll find(ll x){
	return x==p[x]?x:p[x]=find(p[x]);
}
int main(){
	std::ios::sync_with_stdio(false);
	v.resize(maxn);
	ll sum=0;
	cin>>n>>m>>x;
	for(int i=1;i<=n;i++)cin>>a[i],sum+=a[i],p[i]=i;//初始化
	for(int i=1;i<=m;i++){
		int a,b;cin>>a>>b;
		v[a].emplace_back(b,i);v[b].emplace_back(a,i);//存边 second为边标记
	}
	if(sum<1ll*(n-1)*x){puts("NO");return 0;}
	priority_queue<pair<ll,ll>>q;
	for(int i=1;i<=n;i++){//优先队列存点
		pair<ll,ll>temp;
		temp.first=a[i];temp.second=i;
		q.push(temp);
	}
	puts("YES");
	for(int i=1;i<=n-1;i++){
		pair<ll,ll> t=q.top();q.pop();//取出最大
		int u=t.second;
		while(u!=find(u)){//如果该点已被加入并查集
			t=q.top();q.pop();//不停弹出
			u=t.second;
		}//得到的必定为父节点
		while(u==find(v[u].back().first)&&v[u].size())v[u].pop_back();//如果相邻的节点存在同集边则删除
		printf("%d\n",v[u].back().second);//将下一个点加入
		ll vv=find(v[u].back().first);//vv为待加入点的父节点
		a[u]+=a[vv]-x;//合并x值
		pair<ll,ll> tt;tt.first=a[u],tt.second=u;//更新节点u
		q.push(tt);//将tt加入。
		p[vv]=u;//将vv树与u合并
		if(v[u].size()<v[vv].size()){//优化插入 不然会mle
			swap(v[u],v[vv]);
		}
		v[u].insert(v[u].end(),v[vv].begin(),v[vv].end());//将小树插入大树
		v[vv].clear();
	}
	return 0;
}

CR#686(div3)
E. Number of Simple Paths(基环树)
You are given an undirected graph consisting of n vertices and n edges. It is guaranteed that the given graph is connected (i. e. it is possible to reach any vertex from any other vertex) and there are no self-loops and multiple edges in the graph.
Your task is to calculate the number of simple paths of length at least 1 in the given graph. Note that paths that differ only by their direction are considered the same (i. e. you have to calculate the number of undirected paths). For example, paths [1,2,3] and [3,2,1] are considered the same.
You have to answer t independent test cases.
Recall that a path in the graph is a sequence of vertices v1,v2,…,vk such that each pair of adjacent (consecutive) vertices in this sequence is connected by an edge. The length of the path is the number of edges in it. A simple path is such a path that all vertices in it are distinct.

题意:给定一个有n条边n个点的无向图,问存在多少条简单路径
这道题的隐藏条件在于这是一棵基环树,没有挖掘出来的化就会感到无从下手。
知道了之后其实就很简单了,如果两个点在同一棵子树上,只存在一条简单路径,否则则存在两条简单路径,故只需要统计每棵子树的大小最后统计一下额外增加了多少条边即可。

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn=4e5+5;
int size[maxn]={};
int in[maxn]={};
vector<int> edge[maxn]={};
//dfs求子树大小
void dfs(int x,int f){
	size[x]=1;
	for(auto i:edge[x]){
		if(i==f||in[i]>1)//跳过根节点和环上的边
			continue;
		dfs(i,x);
		size[x]+=size[i];
	}
}
int main(){
	int t;cin>>t;
	while(t--){
		int n;cin>>n;
		for(int i=1;i<=n;i++){
			in[i]=0;size[i]=0;edge[i].clear();
		}
		for(int i=1;i<=n;i++){
			int x, y;cin>>x>>y;
			edge[x].push_back(y);
			edge[y].push_back(x);
			in[x]++;
			in[y]++;
		}
		queue<int>q;//拓扑排序判环
		for(int i=1;i<=n;i++){
			if(in[i]==1)q.push(i);
		};
		while(!q.empty()){
			int x=q.front();
			q.pop();
			for(auto y:edge[x]){
				--in[y];
				if(in[y]==1){
					q.push(y);
				}
			}
		}
		//最后如果in数组中入度仍大于1则说明该节点为子树根节点
			vector<int>a;
		//一棵无向无环树的简单路径数
			long long ans=(long long)1*n*(n-1)/2;
	    //求各个子树大小
			for(int i=1;i<=n;i++){
				if(in[i]>1){
					dfs(i,-1);
					a.push_back(size[i]);
				}
			}
		//加上该子树经过环的另一边到其他不同子树所产生的额外的简单路径数
			for(auto i:a){
				ans+=(long long)1*i*(n-i);
				n-=i;
			}
			cout<<ans<<endl;
		}
	return 0;
	}

CR#607(div1)
C. Jeremy Bearimy(贪心)
Welcome! Everything is fine.
You have arrived in The Medium Place, the place between The Good Place and The Bad Place. You are assigned a task that will either make people happier or torture them for eternity.
You have a list of k pairs of people who have arrived in a new inhabited neighborhood. You need to assign each of the 2k people into one of the 2k houses. Each person will be the resident of exactly one house, and each house will have exactly one resident.
Of course, in the neighborhood, it is possible to visit friends. There are 2k−1 roads, each of which connects two houses. It takes some time to traverse a road. We will specify the amount of time it takes in the input. The neighborhood is designed in such a way that from anyone’s house, there is exactly one sequence of distinct roads you can take to any other house. In other words, the graph with the houses as vertices and the roads as edges is a tree.
The truth is, these k pairs of people are actually soulmates. We index them from 1 to k. We denote by f(i) the amount of time it takes for the i-th pair of soulmates to go to each other’s houses.
As we have said before, you will need to assign each of the 2k people into one of the 2k houses. You have two missions, one from the entities in The Good Place and one from the entities of The Bad Place. Here they are:
The first mission, from The Good Place, is to assign the people into the houses such that the sum of f(i) over all pairs i is minimized. Let’s define this minimized sum as G. This makes sure that soulmates can easily and efficiently visit each other;
The second mission, from The Bad Place, is to assign the people into the houses such that the sum of f(i) over all pairs i is maximized. Let’s define this maximized sum as B. This makes sure that soulmates will have a difficult time to visit each other.
What are the values of G and B?
题意:给定一棵树,将树上的点两两配对,求所有点对距离和的最大最小值。
本道题利用贪心即可。将距离和按边拆分,则对于每一条边,最值可视为经过该边的最多路径数和最少路径数。最多路径数便是该边两侧点的数量的最小值,对于最少路径数,将点分为奇偶数讨论,奇数为一条,偶数为零条。对于每条边更新一下相加即可。
该题用到了树的特性,即树的任意一条边均为桥

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define int long long
using namespace std;
const int maxn=2e5+5;
vector <pair<int,int>> G[maxn]={};//带权值邻接表
int ansmin,ansmax;
int n;
int size[maxn]={};
bool vis[maxn]={};
void dfs(int x){
	size[x]=1;
	for(auto y:G[x]){
		if(vis[y.first]==1)continue;
		vis[y.first]=1;
		dfs(y.first);
		size[x]+=size[y.first];//计算以当前节点为根节点的子树的节点大小
		//该节点的入边为当前讨论的桥
		if(size[y.first]%2){//更新最小值
		ansmin+=y.second;
		}
		int r=min(size[y.first],2*n-size[y.first]);
		ansmax+=r*y.second;//更新最大值
	}
}
signed main(){
	int q;cin>>q;while(q--){
		cin>>n;ansmax=0;ansmin=0;
		for(int i=1;i<=2*n;i++){
			size[i]=0;G[i].clear();vis[i]=0;
		}
		int p=2*n-1;
		while(p--){
			pair<int,int> temp;
			int x,y;cin>>x>>y>>temp.second;
			temp.first=x;
			G[y].push_back(temp);
			temp.first=y;
			G[x].push_back(temp);
		}
		dfs(1);//所有边都为桥,故可以从任意节点开始dfs
		cout<<ansmin<<' '<<ansmax<<endl;
	}
	return 0;
}

CR#719(div3)
G. To Go Or Not To Go?(BFS)
Dima overslept the alarm clock, which was supposed to raise him to school.
Dima wonders if he will have time to come to the first lesson. To do this, he needs to know the minimum time it will take him to get from home to school.
The city where Dima lives is a rectangular field of n×m size. Each cell (i,j) on this field is denoted by one number aij:
The number −1 means that the passage through the cell is prohibited;
The number 0 means that the cell is free and Dima can walk though it.
The number x (1≤x≤109) means that the cell contains a portal with a cost of x. A cell with a portal is also considered free.
From any portal, Dima can go to any other portal, while the time of moving from the portal (i,j) to the portal (x,y) corresponds to the sum of their costs aij+axy.
In addition to moving between portals, Dima can also move between unoccupied cells adjacent to one side in time w. In particular, he can enter a cell with a portal and not use it.
Initially, Dima is in the upper-left cell (1,1), and the school is in the lower right cell (n,m).

在这里插入图片描述
题意:给定一张网格图,需要从D点移动至S点,D,S不一定连通。但可以通过地图上存在的传送门传送,可在任意两个门间传送,cost为两传送门给定cost之和,不使用传送门时,每移动一格消耗wcost,求D至S的cost最小值。
很显然,最优解要么用一次传送门,要么不用。对于进入的传送门和传出的传送门,我们可以通过两遍相反的BFS求出最小值,(将传出过程看作从终点出发进入传送门的过程)最后和不用传送门的比较一下就行了。
其实这道题是比较简单的,主要是写起来可能比较麻烦。

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define pii pair<int,int>
#define int long long
using namespace std;
const int maxn=2e3+5;
const int inf = 0x3f3f3f3f3f3f3f;
int cost[maxn][maxn]={};
int a[maxn][maxn]={};
queue<pii>q;
int w;pii h;
bool vis[maxn][maxn]={};
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int n,m;
//检查移动是否合法
bool check(int x,int y){
	if(x<1||x>n||y<1||y>m)return 0;
	if(a[x][y]==-1)return 0;
	return 1;
}
//bfs s1,s2为起始bfs点, t1将返回最优解传送门
int bfs(int s1,int s2,pii &t1){
	cost[s1][s2]=0;
	pii temp;temp.first=s1,temp.second=s2;
	q.push(temp);
	vis[s1][s2]=1;
	int c1=inf;
	//特判,存在bfs起点为传送门的情况
	if(a[s1][s2]>0){
		c1=a[s1][s2];t1.first=s1,t1.second=s2;
	}
	while(q.size()){
		h=q.front();q.pop();
		for(int i=0;i<4;i++){
		//四个方向前进
			int x=h.first+dx[i],y=h.second+dy[i];
		//不合法的行动跳过
			if(!check(x,y)||vis[x][y])continue;
			pii temp;temp.first=x,temp.second=y;
			q.push(temp);
			vis[x][y]=1;
		//更新该点cost
			cost[x][y]=cost[h.first][h.second]+w;
		//存在传送门则更新返回值
			if(a[x][y]){
				int t=a[x][y]+cost[x][y];
				if(t<c1){
					t1.first=x,t1.second=y;
					c1=t;
				}
			}
		}
	}
	return c1;
}
signed main(){
	std::ios::sync_with_stdio(false);
	cin>>n>>m>>w;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
			cost[i][j]=inf;
		}
	}
	//将最佳传送门点初始化为-1,用于判断是否存在可行的使用传送门的路径
	pii t1;t1.first=t1.second=-1;
	pii t2;t2.first=t2.second=-1;
	//求进入传送门最优解
	int c1=bfs(1,1,t1);
	int ans=cost[n][m];//no use
	//清空
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++)vis[i][j]=0;
	}
	//求传出传送门最优解
	int c2=bfs(n,m,t2);
	//存在合法传送门路径
	if(t1.first!=-1&&t2.first!=-1)ans=min(ans,c1+c2);
	//存在合法不用传送门路径
	if(ans==inf)ans=-1;
	cout<<ans;
	return 0;
}

CR#703(div2)
E. Paired Payment(二维dijkstra)
There are n cities and m bidirectional roads in the country. The roads in the country form an undirected weighted graph. The graph is not guaranteed to be connected. Each road has it’s own parameter w. You can travel through the roads, but the government made a new law: you can only go through two roads at a time (go from city a to city b and then from city b to city c) and you will have to pay (wab+wbc)2 money to go through those roads. Find out whether it is possible to travel from city 1 to every other city t and what’s the minimum amount of money you need to get from 1 to t.
题意:给定一无向图,每次只能跳两步,权值为两边和的平方,求单源最短路径。
此题为dij算法的多元形式,
dis[i][j][num]表示从起始点到i经过上一个点为j,所经过总边数为num的最短路径。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e5+1000;
#define int long long
struct node{
	int id,w,val,num;
	friend bool operator<(struct node a,struct node b){
		return a.val>b.val;
	}
};
struct edge{
	int to,val;
};
int dis[maxn][55][3];
bool vis[maxn][55][3];
vector<edge>g[maxn];
int n,m;
void dij(){
	memset(dis,0x3f,sizeof(dis));
	priority_queue<node>que;
	dis[1][0][0]=0;//初始化起始点
	node temp={1,0,0,0};
	que.push(temp);
	while(!que.empty()){
		node now=que.top();
		que.pop();
		if(vis[now.id][now.w][now.num])continue;
		vis[now.id][now.w][now.num]=1;
		int x=now.id;
		for(auto i:g[x]){
			int v=i.to;int w=i.val;
			int cost=0;
			//父节点的num为1,则子节点需要更新cost
			if(now.num==1){
				cost=(now.w+w)*(now.w+w);
			}
			//对于v点
			//如果num为0,那么需要用num为1的u节点加上cost更新
			//如果num为1,那么直接用num为0的u节点直接更新
			//(仅有num为0时才加入新边更新权值,num为1时只是起到了传递最小参数至当前节点的作用)
			if(dis[v][w][now.num^1]>dis[now.id][now.w][now.num]+cost){
				dis[v][w][now.num^1]=dis[now.id][now.w][now.num]+cost;
			//num取反加入优先队列
				node temp={v,w,dis[v][w][now.num^1],now.num^1};
				que.push(temp);
			}
		}
	}
}
signed main(){
	 cin.tie(0);std::ios::sync_with_stdio(false);
	 cin>>n>>m;
	 for(int i=1;i<=m;i++){
		 int u,v,val;cin>>u>>v>>val;
		 edge temp1={v,val};
		 g[u].push_back(temp1);
		 edge temp2={u,val};
		 g[v].push_back(temp2);
	 }
	 dij();
	 for(int i=1;i<=n;i++){
		 long long maxv=1e18;
		 //由于此时的dij为二维,那么需要统计出经过上一个节点的所有情况下最小值的最小值
		 for(int j=0;j<=50;j++){
			 maxv=min(maxv,dis[i][j][0]);
		 }
		 if(maxv==1e18){
			 cout<<"-1"<<' ';
		 }
		 else cout<<maxv<<' ';
	 }
	 cout<<endl;
return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值