李超线段树 学习笔记

昨天做到了这个题:BZOJ4515 [SDOI2016]游戏。发现自己根本不会做,这线段树怎么维护啊。然后才知道有这么个李超线段树。。

标记永久化

李超线段树里面有一个标记永久化的思想,但是我没写过这种题。。大概看了一下。

  • 树套树以及主席树里,区间操作打标记会显得十分的麻烦
  • 可以将lazytag固定,不下传,不pushup的做法是标记永久化
  • 具体可以参考下面那个网址
  • 个人觉得最值得注意的是是一路修改还是pushup
  • 求和的时候有可能pushup儿子的时候儿子处在一个永久化标记下面,他部分信息没有被更新,会出问题,非要用pushup的话,必须累计上走过路线的贡献,及时一路更新更为简便
  • 求最值的时候就必须需要pushup,但是注意要把上面累计上的标记一起放到pushup里面。

可以参考这位的blog

李超线段树

李超线段树的基本功能:

  • 在线动态在平面直角坐标系中插入一些线段/直线
  • 查询与$x=x_0$相交的所有直线里面$y$最小/最大的一个
  • 一些魔改操作,如区间查询、树上修改,详见下面。

板子题:BZOJ3165 [HEOI2013]Segment

  • 如何维护最大值?李超线段树是这样维护线段树信息的:设线段树节点代表横坐标区间,那么节点上维护在这个区间上所有线段中,暴露在最上面的,具体来说,也就是在区间中点处最高的线段,不妨称之为优势线段。记录其$k,b$。
  • 现在假设第一次插入一条线段,先把他在线段树上拆分成若干个完整的区间,这些区间分别处理。在一个区间中,发现没有优势线段,直接插入在这个区间上,不向下递归,立即回去。
  • 可以猜到,这个区间内的某个点查询最大值,答案在这个区间节点上。
  • 现在考虑如果一个区间已经维护了一个线段,现在又插入了该怎么办。
  • 分几类情况讨论。
    • 如果这个新线段整个比旧线段低,肯定不会成为最优解,直接退回。
    • 比旧线段高,那原来这个线段就没用了,修改之后退回。
    • 否则,会有交点。交点在mid坐标左边,那么:
      • 斜率比旧线段大:显然新线段成为了最优势线段,把维护的线段改掉。但是,原来旧线段并不能否定毫无作用,因为左侧交点左边还可能更大,所以我们先把当前旧线段标记下放到左半区间。
      • 斜率比旧线段小:新线段不会成为最优势线段,右半区间不优,左半区间仍可能在交点左侧产生更大值,于是把新线段扔到左半区间继续处理。
    • 交点在mid坐标右边,那么:
      • 斜率比旧线段大:只把新线段下放到右半区间处理。
      • 斜率比旧线段小:把旧线段下放到右半区间,新线段取代之成为当前区间最优势线段。
  • 总的来说,其实就是讨论谁mid的值更大,然后把当前区间较劣势线段下放至交点一侧的区间在修改。
  • 说的不太清楚,可以结合图,看一下这位的配图:神仙
  • 为什么要这样做?下放标记原理在于,当前维护的线段假如是区间内所有线段的最优解,插入了一个新线段之后,有部分点最优解改变。那么为了保证正确维护这些点的最大值,我们不得不将一部分信息下放到对应区间,保留住最大值,查询点的时候,所有包含这个点的区间,或多或少维护了一些线段,其中必定有一个可以产生点$x$上的最大值。这里使用了标记永久化思想,只在整块区间打标记,查询时候一路记录比较,只在有必要时,也就是不得已要保证最大值的时候才下放标记。
  • 维护最优势线段的好处在于每次只需要继续维护一半的区间,降低复杂度,也易于使得标记永久化
  • 复杂度分析:维护线段时,把线段在线段树上分成最多$2logn$块,每块要分别处理,块内最多会下放至底层复杂度$O(logn)$,那么总复杂度$O(log^2n)$。很多时候跑不满。查询单点的时候,一路比较max去最优,复杂度$O(logn)$。
  • 这题总的复杂度$O(nlog^2n)$。

code:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define dbg(x) cerr << #x << " = " << x <<endl
 7 #define dbg2(x,y) cerr << #x << " = " << x << "  " << #y << " = " << y <<endl
 8 using namespace std;
 9 typedef long long ll;
10 typedef double dl;
11 typedef pair<int,int> pii;
12 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
13 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
14 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
15 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
16 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
17 template<typename T>inline T read(T&x){
18     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
19     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
20 }
21 const int N=1e5+7;
22 const dl eps=1e-9;
23 int T,tot;
24 struct seg{
25     dl k,b;int id;
26     seg(dl k=0,dl b=0,int id=0):k(k),b(b),id(id){}
27 };
28 inline int chk(dl x,dl y){return x-y>=eps?1:(x-y<=-eps?-1:0);}
29 struct Lc_segment_tree{
30     seg s[N<<2];
31     #define lc i<<1
32     #define rc i<<1|1
33     inline void Pushdown(int i,int L,int R,seg c){
34         if(!s[i].id){s[i]=c;return;}
35         int mid=L+R>>1;
36         dl l1=s[i].k*L+s[i].b,r1=s[i].k*R+s[i].b;
37         dl l2=c.k*L+c.b,r2=c.k*R+c.b;
38         if(~chk(l1,l2)&&~chk(r1,r2))return;
39         if(l2>l1&&r2>r1){s[i]=c;return;}//go back when arriving leaf
40         dl x=(s[i].b-c.b)/(c.k-s[i].k);
41         if(x<=mid){
42             Pushdown(lc,L,mid,r1<r2?s[i]:c);    
43             if(r1<r2)s[i]=c;
44         }
45         else{
46             Pushdown(rc,mid+1,R,r1<r2?c:s[i]);
47             if(r1>r2)s[i]=c;
48         }
49     }
50     inline void Update(int i,int L,int R,int ql,int qr,seg c){
51         if(ql<=L&&qr>=R){Pushdown(i,L,R,c);return;}
52         int mid=L+R>>1;
53         if(ql<=mid)Update(lc,L,mid,ql,qr,c);
54         if(qr>mid)Update(rc,mid+1,R,ql,qr,c);
55     }
56     inline void QMAX(seg&a,seg b,int x){
57         dl ya=a.k*x+a.b,yb=b.k*x+b.b;
58         if(ya<yb||!chk(ya,yb)&&a.id>b.id)a=b;
59     }
60     inline seg Query_max(int i,int L,int R,int x){
61         if(L==R)return s[i];
62         int mid=L+R>>1;seg ret=s[i];
63         if(x<=mid)QMAX(ret,Query_max(lc,L,mid,x),x);
64         else QMAX(ret,Query_max(rc,mid+1,R,x),x);
65         return ret;
66     }
67 }thxorz;
68 #define all 1,1,39989
69 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
70     read(T);
71     for(register int i=1,opt,x1,x2,y1,y2,las=0;i<=T;++i){
72         read(opt);dl k;
73         if(opt){
74             read(x1),read(y1),read(x2),read(y2);
75             x1=(x1+las-1)%39989+1,y1=(y1+las-1)%1000000000+1;
76             x2=(x2+las-1)%39989+1,y2=(y2+las-1)%1000000000+1;//mistake.
77             if(x1>x2)swap(x1,x2),swap(y1,y2);
78             if(x1==x2)thxorz.Update(all,x1,x2,seg(0,_max(y1,y2),++tot));
79             else k=(dl)(y2-y1)/(x2-x1),thxorz.Update(all,x1,x2,seg(k,y1-k*x1,++tot));
80         }
81         else{
82             read(x1);x1=(x1+las-1)%39989+1;
83             printf("%d\n",las=thxorz.Query_max(all,x1).id);
84         }
85     }
86     return 0;
87 }
有点丑呢。。。

个人是从这里学会的,代码是模仿yyb的。。ORZ

拓展

那么现在看来,李超线段树也就不难理解了。于是有一些魔改。

BZOJ1568 [JSOI2008]Blue Mary开公司

这题是一个直线修改,也就是直接从线段树根节点就开始下放了。复杂度$O(nlogn)$。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define dbg(x) cerr << #x << " = " << x <<endl
 7 using namespace std;
 8 typedef long long ll;
 9 typedef double db;
10 typedef pair<int,int> pii;
11 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
12 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
16 template<typename T>inline T read(T&x){
17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
19 }
20 const int N=50000+7;
21 const db eps=1e-9;
22 struct seg{
23     db k,b;int vis;
24     seg(db k=0,db b=0,int vis=0):k(k),b(b),vis(vis){}
25 };
26 inline int chk(db x,db y){return x-y>=eps?1:(x-y<=-eps?-1:0);}
27 struct lc_segment_tree{
28     seg s[N<<2];
29     #define lc i<<1
30     #define rc i<<1|1
31     inline void Pushdown(int i,int L,int R,seg c){
32         if(!s[i].vis){s[i]=c;return;}
33         db l1=s[i].k*L+s[i].b,r1=s[i].k*R+s[i].b;
34         db l2=c.k*L+c.b,r2=c.k*R+c.b;
35         if(~chk(l1,l2)&&~chk(r1,r2))return;
36         if(l1<l2&&r1<r2){s[i]=c;return;}
37         int mid=L+R>>1;db x=(c.b-s[i].b)/(s[i].k-c.k);
38         if(x<=mid){
39             Pushdown(lc,L,mid,r1<r2?s[i]:c);
40             if(r1<r2)s[i]=c;
41         }
42         else{
43             Pushdown(rc,mid+1,R,r1>r2?s[i]:c);
44             if(r1>r2)s[i]=c;
45         }
46     }
47     inline void Update(int i,int L,int R,int ql,int qr,seg c){
48         if(ql<=L&&qr>=R){Pushdown(i,L,R,c);return;}
49         int mid=L+R>>1;
50         if(ql<=mid)Update(lc,L,mid,ql,qr,c);
51         if(qr>mid)Update(rc,mid+1,R,ql,qr,c);
52     }
53     inline db Query_max(int i,int L,int R,int x){
54         if(L==R)return s[i].k*x+s[i].b;
55         int mid=L+R>>1;db ret=_max(0.0,s[i].k*x+s[i].b);//注意无线段保存时的正确性qwq但这里不需要 
56         if(x<=mid)MAX(ret,Query_max(lc,L,mid,x));
57         else MAX(ret,Query_max(rc,mid+1,R,x));
58         return ret;
59     }
60 }stothx;
61 int T,x;
62 char s[14];
63 db k,b;
64 #define all 1,1,50000
65 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
66     read(T);while(T--){
67         scanf("%s",s);
68         if(s[0]=='P')scanf("%lf%lf",&b,&k),stothx.Update(all,1,50000,seg(k,b-k,1));
69         else read(x),printf("%d\n",(int)stothx.Query_max(all,x)/100);
70 //        else read(x),printf("%f\n",stothx.Query_max(all,x));
71     }
72     return 0;
73 }
View Code

如果把查询范围改到$1e9$呢?两种方法。

  1. 离散化询问坐标,然后在离散化坐标上建成线段树,这时注意一下区间上的$L,R$和原来概念就不一样惹。
  2. 动态开点。没写。

BZOJ4515 [SDOI2016]游戏

当把问题放到树上,就非常毒瘤了。。这题我写了1h,调代码调了2~3h,肝要爆了。。。

问题是从带边权的树上一个起点到终点路上每个节点和$a*dis+b$($a,b$给定,$dis$是距离起点的距离)取最小值。

  • 最小基本就是修改一下,但是注意一下对应节点上不存在的话要返回INF。
  • 树上问题采用树剖分成若干条链,然后一条链对应了dfs序连续一段区间。
  • 然后这个$a*dis+b$和李超线段树维护内容相似,考虑怎么维护每一条重链。
  • 相当于在线段树上一段连续区间上插入线段。但是,这个区间的每个点横坐标不固定唉。。因为每次修改的$dis$是变的。
  • 考虑让他固定死。对于上行段,$a*dis+b=a(depth_s-depth_i)+b=-a*depth_i+a*depth_s+b$,成为了一个标准的斜截式。
  • 下行段,$a*dis+b=a(depth_s+depth_i-2depth_{lca})+b=a*depth_i+a*depth_s-2a*depth_{lca}+b$。
  • 分上下行维护就好了。
  • 这告诉我们李超线段树注重的是整块的区间,只要添加线段的区间内的横坐标是递增的,维护就没问题。
  • 还有一个问题:区间(树链)查询最小值。
  • 发现这个可以对每个区间开一个$minv$维护,表示维护这个区间子树内所有点在所有线段上出现的最小值。也就是说,为了区间查询在$O(logn)$级别,我们在递归到整块区间的时候必须直接返回这个$minv$保证复杂度。
  • 那么,在pushdown操作中,要及时维护这个信息,在update函数中也要不断pushup。(具体看code)
  • 这样查询时一路计算,到整块直接返回,保证复杂度。
  • 时间总复杂度$O(nlog^3n)$。因为树剖和李超线段树常数都比较小。。所以可以过。
  • 毒瘤题!

我写的时候犯了很多错误,再一次反应了自己基本功不扎实。。。

特别注意一个query操作,传参$ql和qr$不是正常线段树的传法!为了一路计算比较,必须修改部分。同时树剖也有部分魔改。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 #define dbg(x) cout << #x << " = " << x <<endl
  7 using namespace std;
  8 typedef long long ll;
  9 typedef double db;
 10 typedef pair<int,int> pii;
 11 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
 12 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
 13 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
 14 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
 15 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
 16 template<typename T>inline T read(T&x){
 17     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
 18     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
 19 }
 20 const int N=1e5+7;
 21 const ll INF=123456789123456789;
 22 struct tree{int to,nxt,w;}G[N<<1];
 23 int Head[N],tot;
 24 int n,q;
 25 inline void Addedge(int x,int y,int z){
 26     G[++tot].to=y,G[tot].nxt=Head[x],Head[x]=tot,G[tot].w=z;
 27     G[++tot].to=x,G[tot].nxt=Head[y],Head[y]=tot,G[tot].w=z;
 28 }
 29 #define y G[j].to
 30 ll dep[N];
 31 int st[N],pos[N],tim,son[N],fa[N],topfa[N],fl[N],cnt[N];
 32 void dfs1(int x,int f){
 33     fa[x]=f;int tmp=-1;cnt[x]=1;fl[x]=fl[f]+1;
 34     for(register int j=Head[x];j;j=G[j].nxt)if(y^f)
 35         dep[y]=dep[x]+G[j].w,dfs1(y,x),cnt[x]+=cnt[y],MAX(tmp,cnt[y])&&(son[x]=y);
 36 }//mistake line 36:counting sons/difference between floor and depth 
 37 void dfs2(int x,int topf){
 38     topfa[x]=topf,st[x]=++tim,pos[tim]=x;if(!son[x])return;dfs2(son[x],topf);
 39     for(register int j=Head[x];j;j=G[j].nxt)if((y!=fa[x])&&(y!=son[x]))dfs2(y,y);
 40 }//mistake line39 Head[x]
 41 #undef y
 42 struct seg{
 43     ll k,b;int vis;
 44     seg(ll k=0,ll b=0,int vis=0):k(k),b(b),vis(vis){}
 45 };
 46 struct lc_segment_tree{
 47     seg s[N<<2];ll minv[N<<2];
 48     #define lc i<<1
 49     #define rc i<<1|1
 50     #define lb dep[pos[L]]
 51     #define rb dep[pos[R]]
 52     #define calc(c,x) (c.k*x+c.b)
 53     inline void Pushup(int i){MIN(minv[i],_min(minv[lc],minv[rc]));}
 54     void Pushdown(int i,int L,int R,seg c){//dbg(calc(c,lb)),dbg(calc(c,rb));
 55         if(!s[i].vis){s[i]=c;MIN(minv[i],_min(calc(c,lb),calc(c,rb)));return;}
 56         ll l1=calc(s[i],lb),r1=calc(s[i],rb),l2=calc(c,lb),r2=calc(c,rb);
 57         if(l1<=l2&&r1<=r2)return;
 58         if(l1>l2&&r1>r2){s[i]=c;MIN(minv[i],_min(l2,r2));return;}
 59         int mid=L+R>>1;
 60         db x=(db)(c.b-s[i].b)/(s[i].k-c.k);
 61         if(x<=dep[pos[mid]]){
 62             Pushdown(lc,L,mid,r1<r2?c:s[i]);
 63             if(r1>r2)s[i]=c,MIN(minv[i],r2);
 64             else MIN(minv[i],minv[lc]);
 65         }
 66         else{
 67             Pushdown(rc,mid+1,R,r1<r2?s[i]:c);
 68             if(r1<r2)s[i]=c,MIN(minv[i],l2);
 69             else MIN(minv[i],minv[rc]);//mistake:remember to pushup after pushdowning
 70         }
 71     }
 72     void Update(int i,int L,int R,int ql,int qr,seg c){//dbg(L),dbg(R),dbg(ql),dbg(qr);
 73         if(ql<=L&&qr>=R){Pushdown(i,L,R,c);return;}
 74         int mid=L+R>>1;
 75         if(ql<=mid)Update(lc,L,mid,ql,qr,c);
 76         if(qr>mid)Update(rc,mid+1,R,ql,qr,c);
 77         Pushup(i);
 78     }
 79     ll Query(int i,int L,int R,int ql,int qr){//dbg(L),dbg(R),dbg(ql),dbg(qr),dbg(minv[i]);
 80         if(ql<=L&&qr>=R)return minv[i];
 81         int mid=L+R>>1;
 82         ll ret=s[i].vis?_min(calc(s[i],dep[pos[ql]]),calc(s[i],dep[pos[qr]])):INF;
 83         if(qr<=mid)MIN(ret,Query(lc,L,mid,ql,qr));
 84         else if(ql>mid)MIN(ret,Query(rc,mid+1,R,ql,qr));
 85         else MIN(ret,Query(lc,L,mid,ql,mid)),MIN(ret,Query(rc,mid+1,R,mid+1,qr));//mistake:distinguish ql,qr,L,R!线段树板子背的过于熟练于是疏忽了 
 86         return ret;
 87     }
 88 }T;
 89 inline int LCA(int x,int y){
 90     while(topfa[x]^topfa[y])fl[topfa[x]]<fl[topfa[y]]?y=fa[topfa[y]]:x=fa[topfa[x]];
 91     return fl[x]<fl[y]?x:y;
 92 }
 93 inline void Modify(int s,int t,int a,int b){
 94     int lca=LCA(s,t),tmp=s;
 95     ll K=-a,B=a*dep[s]+b;
 96     while(topfa[s]^topfa[lca])T.Update(1,1,n,st[topfa[s]],st[s],seg(K,B,1)),s=fa[topfa[s]];
 97     T.Update(1,1,n,st[lca],st[s],seg(K,B,1));
 98     K=a,B=a*(dep[tmp]-(dep[lca]<<1))+b;//mistake:tmp and s!
 99     while(topfa[t]^topfa[lca])T.Update(1,1,n,st[topfa[t]],st[t],seg(K,B,1)),t=fa[topfa[t]];
100     T.Update(1,1,n,st[lca],st[t],seg(K,B,1));
101 }
102 inline ll Query(int s,int t){
103     ll ret=INF;ll tmp;
104     while(topfa[s]^topfa[t]){
105         if(fl[topfa[s]]<fl[topfa[t]])s^=t^=s^=t;
106         MIN(ret,tmp=T.Query(1,1,n,st[topfa[s]],st[s])),s=fa[topfa[s]];//miskate:I've mixed the 'st' and 'id' up
107     }
108     MIN(ret,fl[s]<fl[t]?T.Query(1,1,n,st[s],st[t]):T.Query(1,1,n,st[t],st[s]));
109     return ret;
110 }
111 
112 int main(){//freopen("8.in","r",stdin);freopen("8.ans","w",stdout);
113     read(n),read(q);
114     for(register int i=1,x,y,z;i<n;++i)read(x),read(y),read(z),Addedge(x,y,z);
115     dfs1(1,0),dfs2(1,1);
116     for(register int i=1;i<=n<<2;++i)T.minv[i]=INF;
117     for(register int i=1,opt,s,t,a,b;i<=q;++i){
118         read(opt);
119         if(opt==1)read(s),read(t),read(a),read(b),Modify(s,t,a,b);
120         else read(s),read(t),printf("%lld\n",Query(s,t));
121     }
122     return 0;
123 }
124 //AC:1/3
View Code
1 /***********************************************
2 line36:树剖好久不写,找重儿子都找错了。。
3 line31:注意fl(floor)和dep(depth)的区别,前面是用作树剖跳的,后者是算横坐标的。
4 line39:typo
5 line64,69:记得更新好minv
6 line85:重点错误,已解释
7 line98:s跳过之后就不是原来的s了。。
8 line106:typo
9 ***********************************************/丢人现眼
丢人现眼的错误

转载于:https://www.cnblogs.com/saigyouji-yuyuko/p/11574763.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用和提到,Linux下安装ffmpeg是非常方便的。下面给出在Linux上安装ffmpeg的步骤: 1. 首先,需要安装Cygwin。Cygwin是一个在Windows上运行类似于Linux的环境的工具。可以从官方网站上下载并安装。 2. 安装完Cygwin后,打开终端,输入以下命令下载x264源代码并进行编译: ``` wget http://mirror.yandex.ru/mirrors/ftp.videolan.org/x264/snapshots/last_x264.tar.bz2 bunzip2 last_x264.tar.bz2 tar -vxf last_x264.tar cd last_x264 ./configure --enable-static --enable-shared --disable-asm --disable-avs make && sudo make install ``` 3. 然后,从ffmpeg官网下载ffmpeg源代码,并进行编译。编译方法可以参考官方文档或者在终端中输入以下命令: ``` wget http://ffmpeg.org/releases/ffmpeg-[版本号].tar.gz tar -xzvf ffmpeg-[版本号].tar.gz cd ffmpeg-[版本号] ./configure --enable-shared make sudo make install ``` 其中,是你想要安装的ffmpeg的版本号。 4. 编译完成后,就可以使用ffmpeg了。可以通过在终端中输入`ffmpeg`命令来验证是否安装成功。 请注意,以上步骤仅适用于在Linux系统上安装ffmpeg。如果你是在其他操作系统上进行安装,请参考相关的文档或者教程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Windows下编译安装 FFmpeg](https://blog.csdn.net/heng615975867/article/details/119821945)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值