[HNOI2016] 网络 题解

[HNOI2016] 网络 题解


题意简述

给定一棵 \(n\) 个点的树,以及 \(m\) 个操作:

  1. 0 a b v:点 \(a,b\) 间连上一条权值为 \(v\) 的虚边。
  2. 1 t:删除 \(t\) 时刻连的虚边。
  3. 2 x:查询所有两端点在原树上路径不经过 \(x\) 的虚边的权值中,最大的一个,没有则为 \(-1\)

分析

\(30\%\)

\(m \le 2000\),每次询问遍历所有的虚边,然后进行一系列细节多得要死的判断即可,\(O(m^2)\)\(O(m^2\log_2{n})\) 皆可。

\(20\%\)

第一次事件必定是加入权值最大的虚边,且没有删除操作。

大致思路:把第一次加入的虚边的路径当成一排根,分别遍历子树,然后把加入的虚边再在一排根上做一个前缀、后缀的取最值操作,用线段树实现(还有诸多细节自己想)。

时间复杂度 \(O(m\log_2{n})\)

\(20\%\)

树是一条链,且满足 \(i\)\(i+1\) 之间有边。

直接线段树套可删的堆(set<int> 或双 priority_queue<int>),也是做一个前后缀的操作。

时间复杂度 \(O(m(\log_2{n}+\log_2{m}))\)

//#define Plus_Cat ""
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define FOR(i,a,b) for(int i(a); i<=(int)(b); ++i)
#define DOR(i,a,b) for(int i(a); i>=(int)(b); --i)
#define EDGE(g,i,x,y) for(int i(g.h[x]),y(g[i].v); ~i; y=g[i=g[i].nxt].v)
using namespace std;
constexpr int N(1e5+10),M(2e5+10),lN(17),lV(lN+1);

namespace IOEcat {
#define isD(c) ('0'<=(c)&&(c)<='9')
#define DE(...) E(#__VA_ARGS__,__VA_ARGS__)
	struct Icat {

		char getc() {
			return getchar();
		}

		template<class T>void operator ()(T &x) {
			static bool sign(0);
			static char ch(0);
			sign=0,x=0;
			while(ch=getc(),!isD(ch))if(ch=='-')sign=1;
			do x=(x<<1)+(x<<3)+(ch^48);
			while(ch=getc(),isD(ch));
			if(sign)x=-x;
		}

		template<class T,class...Types>void operator ()(T &x,Types&...args) {
			return (*this)(x),(*this)(args...);
		}

	} I;
	struct Ocat {

		void putc(char c) {
			putchar(c);
		}

		template<class T>void operator ()(T x,const char lst='\n') {
			static int top(0);
			static char st[100];
			if(x<0)x=-x,putc('-');
			do st[++top]=(x%10)^48,x/=10;
			while(x);
			while(top)putc(st[top--]);
			putc(lst);
		}

		template<class T,class...Types>void operator ()(const T x,const char lst='\n',const Types...args) {
			return (*this)(x,lst),(*this)(args...);
		}

	} O;
	struct Ecat {

		template<class T>void operator ()(const char *fmt,const T x) {
			cerr<<fmt<<':'<<x<<'.'<<endl;
		}

		template<class T,class...Types>void operator ()(const char *fmt,const T x,const Types...args) {
			while(*fmt^',')cerr<<*fmt++;
			return cerr<<':'<<x<<" ,",(*this)(++fmt,args...);
		}

	} E;

} using namespace IOEcat;

bool del[M];
int n,m,idx;
int dl[N],dr[N],dep[N];
int fa[N][lV];
vector<int> g[N];
struct Change {
	int t,a,b,c;
} Cha[M];
	
void dfs(int u) {
	dl[u]=++idx,dep[u]=dep[fa[u][0]]+1;
	FOR(i,1,lN)fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int v:g[u])if(v^fa[u][0])fa[v][0]=u,dfs(v);
	dr[u]=idx;
}
	
bool rela(int u,int pa) {
	return dl[pa]<=dl[u]&&dr[u]<=dr[pa];
}

int lca(int u,int v) {
	if(dep[u]>dep[v])swap(u,v);
	DOR(i,lN,0)if((dep[v]-dep[u])&1<<i)v=fa[v][i];
	if(u==v)return u;
	DOR(i,lN,0)if(fa[u][i]^fa[v][i])u=fa[u][i],v=fa[v][i];
	return fa[u][0];
}

namespace Subtask1 { /*30%*/ /*O(m^2log_2{n})*/
	
	bool Check() {
		return m<=2000;
	}
	
	int Cmain() {
		dfs(1);
		FOR(i,1,m) {
			if(Cha[i].t==1)del[Cha[i].a]=1;
			else if(Cha[i].t==2){
				int ans(-1);
				FOR(j,1,i-1)if(!Cha[j].t&&!del[j]&&Cha[j].a!=Cha[i].a&&Cha[j].b!=Cha[i].a&&
					rela(Cha[j].a,Cha[i].a)==rela(Cha[j].b,Cha[i].a)&&lca(Cha[j].a,Cha[j].b)!=Cha[i].a)
						tomax(ans,Cha[j].c);
				O(ans,'\n');
			}
		}
		return 0;
	}
	
}

struct SEG {
#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((l+r)>>1)
	int tr[N<<2];
	multiset<int> st[N<<2];
	
	void Build(int p=1,int l=1,int r=n) {
		if(l==r)return tr[p]=-1,void();
		Build(ls,l,mid),Build(rs,mid+1,r),Up(p);
	}
	
	void Up(int p) {
		tr[p]=max(tr[ls],tr[rs]);
	}
	
	void Insert(int x,int d,int p=1,int l=1,int r=n) {
		if(l==r)return st[p].insert(d),tr[p]=*st[p].rbegin(),void();
		return (x<=mid?Insert(x,d,ls,l,mid):Insert(x,d,rs,mid+1,r)),Up(p);
	}
	
	void Delete(int x,int d,int p=1,int l=1,int r=n) {
		if(l==r)return st[p].erase(st[p].find(d)),tr[p]=st[p].empty()?-1:*st[p].rbegin(),void();
		return (x<=mid?Delete(x,d,ls,l,mid):Delete(x,d,rs,mid+1,r)),Up(p);
	}
	
	int Max(int L,int R,int p=1,int l=1,int r=n) {
		if(L<=l&&r<=R)return tr[p];
		if(R<=mid)return Max(L,R,ls,l,mid);
		if(mid<L)return Max(L,R,rs,mid+1,r);
		return max(Max(L,R,ls,l,mid),Max(L,R,rs,mid+1,r));
	}
	
#undef ls
#undef rs
#undef mid
} Pre,Suf;

namespace Subtask2 { /*20%*/
	constexpr int Lim(1e9);
	int mx(-1),U,V,P,tot;
	int rt[N],idx[N];
	
	bool Check() {
		return !Cha[1].t&&Cha[1].c==Lim;
	}
	
	void _dfs(int u,int fa) {
		for(int v:g[u])if(v!=fa&&!idx[v])rt[v]=rt[u],_dfs(v,u);
	}
	
	int Cmain() {
		Pre.Build(),Suf.Build();
		dfs(1),U=Cha[1].a,V=Cha[1].b,P=lca(U,V),tot=dep[U]-dep[P]+dep[V]-dep[P]+1;
		for(int x(U),it(1);dep[x]>=dep[P];x=fa[x][0],++it)idx[x]=it;
		for(int x(V),it(tot);dep[x]>=dep[P];x=fa[x][0],--it)idx[x]=it;
		FOR(i,1,n)if(idx[i])rt[i]=i,_dfs(i,0);
		FOR(i,1,m) {
			if(Cha[i].t==0) {
				int pa(lca(Cha[i].a,Cha[i].b));
//				DE(i,rt[Cha[i].a],rt[Cha[i].b],Cha[i].c);
				if(rt[Cha[i].a]==rt[Cha[i].b]&&pa!=rt[Cha[i].a]&&(tomax(mx,Cha[i].c),1))continue;
				int l(idx[rt[Cha[i].a]]),r(idx[rt[Cha[i].b]]);
				if(l>r)swap(l,r);
				Pre.Insert(r,Cha[i].c),Suf.Insert(l,Cha[i].c);
			} else if(Cha[i].t==2) {
				if(!idx[Cha[i].a]&&(O(Lim,'\n'),1))continue;
				int ans(mx),u(idx[Cha[i].a]);
//				DE("DFSL",u);
				if(u>1)tomax(ans,Pre.Max(1,u-1));
				if(u<tot)tomax(ans,Suf.Max(u+1,tot));
				O(ans,'\n');
			}
		}
		return 0;
	}
	
}

namespace Subtask3 { /*20%*/

	bool Check() {
		FOR(i,1,n-1) {
			bool flag(0);
			for(int j:g[i])flag|=(j==i+1);
			if(!flag)return 0;
		}
		return 1;
	}
	
	int Cmain() {
		Pre.Build(),Suf.Build();
		FOR(i,1,m) {
			if(Cha[i].t==0) {
				int l(Cha[i].a),r(Cha[i].b);
				if(l>r)swap(l,r);
				Pre.Insert(r,Cha[i].c),Suf.Insert(l,Cha[i].c);
			} else if(Cha[i].t==1) {
				int l(Cha[Cha[i].a].a),r(Cha[Cha[i].a].b);
				if(l>r)swap(l,r);
				Pre.Delete(r,Cha[Cha[i].a].c),Suf.Delete(l,Cha[Cha[i].a].c);
			} else {
				int ans(-1),u(Cha[i].a);
				if(u>1)tomax(ans,Pre.Max(1,u-1));
				if(u<n)tomax(ans,Suf.Max(u+1,n));
				O(ans,'\n');
			}
		}
		return 0;
	}
	
}

int main() {
#ifdef Plus_Cat
	freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
	I(n,m);
	FOR(i,2,n) {
		int u,v;
		I(u,v),g[u].push_back(v),g[v].push_back(u);
	}
	FOR(i,1,m)if(I(Cha[i].t,Cha[i].a),!Cha[i].t)I(Cha[i].b,Cha[i].c);
	if(Subtask1::Check())return Subtask1::Cmain();
	if(Subtask2::Check())return Subtask2::Cmain();
	if(Subtask3::Check())return Subtask3::Cmain();
	return 0;
}

\(100\%\)

树剖+线段树套可删堆

注意:该做法略卡时空。

我们尝试把链的部分分修改一下套到树上来:发现可以重链剖分,然后每次加入操作把不在 \(a,b\) 路径上的点都加入一个权值,单次操作最多 \(O(\log_2{n})\) 个加入区间,线段树区间操作 \(O(\log_2{n}\log_2{m})\),故加入操作的时间复杂度为 \(O(\log_2^2{n}\log_2{m})\) 的。删除同理。

询问直接单点查询即可,复杂度 \(O(\log_2{n}+\log_2{m})\)

故总时间复杂度 \(O(m\log_2^2{n}\log_2{m})\),空间复杂度 \(O(m\log_2^2{n})\)

//#define Plus_Cat ""
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define FOR(i,a,b) for(int i(a); i<=(int)(b); ++i)
#define DOR(i,a,b) for(int i(a); i>=(int)(b); --i)
#define EDGE(g,i,x,y) for(int i(g.h[x]),y(g[i].v); ~i; y=g[i=g[i].nxt].v)
using namespace std;
constexpr int N(1e5+10),M(2e5+10),lN(17),lV(lN+1);

namespace IOEcat {
#define isD(c) ('0'<=(c)&&(c)<='9')
#define DE(...) E(#__VA_ARGS__,__VA_ARGS__)
	struct Icat {

		char getc() {
			return getchar();
		}

		template<class T>void operator ()(T &x) {
			static bool sign(0);
			static char ch(0);
			sign=0,x=0;
			while(ch=getc(),!isD(ch))if(ch=='-')sign=1;
			do x=(x<<1)+(x<<3)+(ch^48);
			while(ch=getc(),isD(ch));
			if(sign)x=-x;
		}

		template<class T,class...Types>void operator ()(T &x,Types&...args) {
			return (*this)(x),(*this)(args...);
		}

	} I;
	struct Ocat {

		void putc(char c) {
			putchar(c);
		}

		template<class T>void operator ()(T x,const char lst='\n') {
			static int top(0);
			static char st[100];
			if(x<0)x=-x,putc('-');
			do st[++top]=(x%10)^48,x/=10;
			while(x);
			while(top)putc(st[top--]);
			putc(lst);
		}

		template<class T,class...Types>void operator ()(const T x,const char lst='\n',const Types...args) {
			return (*this)(x,lst),(*this)(args...);
		}

	} O;
	struct Ecat {

		template<class T>void operator ()(const char *fmt,const T x) {
			cerr<<fmt<<':'<<x<<'.'<<endl;
		}

		template<class T,class...Types>void operator ()(const char *fmt,const T x,const Types...args) {
			while(*fmt^',')cerr<<*fmt++;
			return cerr<<':'<<x<<" ,",(*this)(++fmt,args...);
		}

	} E;

} using namespace IOEcat;

int n,m,idx;
int a[M],b[M],c[M],dl[N],fa[N],dep[N],siz[N],son[N],top[N];
pair<int,int> tmp[lV<<3];
struct CFS {
	int tot,h[N];
	struct edge {
		int v,nxt;
		edge(int v=0,int nxt=0):v(v),nxt(nxt) {}
	} e[N<<1];
	
	edge &operator [](int i) {
		return e[i];
	}
	
	void Init(int n) {
		tot=-1,RCL(h+1,-1,int,n);
	}
	
	void att(int u,int v) {
		e[++tot]=edge(v,h[u]),h[u]=tot;
	}
	
	void con(int u,int v) {
		att(u,v),att(v,u);
	}
	
} g;
struct SEG {
#define ls (p<<1)
#define rs (p<<1|1)
#define mid ((l+r)>>1)
	struct DHP {
		priority_queue<int> S,T;
		
		void update() {
			while(!S.empty()&&!T.empty()&&S.top()==T.top())S.pop(),T.pop();
		}
		
		void push(int x) {
			S.push(x);
		}
		
		void pop(int x) {
			T.push(x);
		}
		
		int top() {
			return update(),S.empty()?-1:S.top();
		}
		
	} tr[N<<2];
	
	template<const bool ty>void Update(int L,int R,int d,int p=1,int l=1,int r=n) {
		if(L<=l&&r<=R)return !ty?tr[p].push(d):tr[p].pop(d);
		if(L<=mid)Update<ty>(L,R,d,ls,l,mid);
		if(mid<R)Update<ty>(L,R,d,rs,mid+1,r);
	}
	
	int Max(int x,int p=1,int l=1,int r=n) {
		if(l==r)return tr[p].top();
		return max(tr[p].top(),x<=mid?Max(x,ls,l,mid):Max(x,rs,mid+1,r));
	}
	
#undef ls
#undef rs
#undef mid
} seg;
	
void dfs0(int u) {
	dep[u]=dep[fa[u]]+1,siz[u]=1,son[u]=0;
	EDGE(g,i,u,v)if(v^fa[u])fa[v]=u,dfs0(v),siz[u]+=siz[v],son[u]=(siz[son[u]]>siz[v]?son[u]:v);
}

void dfs1(int u) {
	dl[u]=++idx;
	if(son[u])top[son[u]]=top[u],dfs1(son[u]);
	EDGE(g,i,u,v)if(v!=fa[u]&&v!=son[u])top[v]=v,dfs1(v);
}
template<const bool ty>void Update(int u,int v,int w) {
	int it(0),tot(0);
	for(; top[u]^top[v]; tmp[++tot]=pair<int,int>(dl[top[v]],dl[v]),v=fa[top[v]])
		if(dep[top[u]]>dep[top[v]])swap(u,v);
	if(dep[u]>dep[v])swap(u,v);
	tmp[++tot]=pair<int,int>(dl[u],dl[v]),sort(tmp+1,tmp+tot+1);
	FOR(i,1,tot) {
		if(tmp[i].first-1>it)seg.Update<ty>(it+1,tmp[i].first-1,w);
		tomax(it,tmp[i].second);
	}
	if(it<n)seg.Update<ty>(it+1,n,w);
}

int main() {
#ifdef Plus_Cat
	freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
	I(n,m),g.Init(n);
	FOR(i,2,n) {
		int u,v;
		I(u,v),g.con(u,v);
	}
	dfs0(1),top[1]=1,dfs1(1);
	FOR(i,1,m) {
		int t;
		switch(I(t,a[i]),t) {
			case 0: {
				I(b[i],c[i]),Update<0>(a[i],b[i],c[i]);
				break;
			}
			case 1: {
				Update<1>(a[a[i]],b[a[i]],c[a[i]]);
				break;
			}
			case 2: {
				O(seg.Max(dl[a[i]]),'\n');
				break;
			}
		}
	}
	return 0;
}

整体二分

这个做法与上面的部分分完全无关……

我们二分答案,然后将操作按原询问序列排序,然后按序遍历,把权值大于中值 \(mid\) 的虚边尝试用树状数组或线段树实现树上差分:在端点处 \(+1\),在 LCA 以及 LCA 的父节点处 \(-1\),这样查询时查子树权值和就可以得到有几条虚边经过自己;查询时判断是不是所有边都经过自己,如果是,代表 \(mid\) 对于这个询问过大,放到左边,否则放到右边。

总时间复杂度 \(O(m\log_2{n}\log_2{m})\)

//#define Plus_Cat ""
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define RCL(a,b,c,d) memset(a,b,sizeof(c)*(d))
#define tomin(a,...) ((a)=min({(a),__VA_ARGS__}))
#define tomax(a,...) ((a)=max({(a),__VA_ARGS__}))
#define FOR(i,a,b) for(int i(a); i<=(int)(b); ++i)
#define DOR(i,a,b) for(int i(a); i>=(int)(b); --i)
#define EDGE(g,i,x,y) for(int i(g.h[x]),y(g[i].v); ~i; y=g[i=g[i].nxt].v)
using namespace std;
constexpr int N(1e5+10),M(2e5+10),lN(17),lV(lN+1);

namespace IOEcat {
#define isD(c) ('0'<=(c)&&(c)<='9')
#define DE(...) E(#__VA_ARGS__,__VA_ARGS__)
	struct Icat {

		char getc() {
			return getchar();
		}

		template<class T>void operator ()(T &x) {
			static bool sign(0);
			static char ch(0);
			sign=0,x=0;
			while(ch=getc(),!isD(ch))if(ch=='-')sign=1;
			do x=(x<<1)+(x<<3)+(ch^48);
			while(ch=getc(),isD(ch));
			if(sign)x=-x;
		}

		template<class T,class...Types>void operator ()(T &x,Types&...args) {
			return (*this)(x),(*this)(args...);
		}

	} I;
	struct Ocat {

		void putc(char c) {
			putchar(c);
		}

		template<class T>void operator ()(T x,const char lst='\n') {
			static int top(0);
			static char st[100];
			if(x<0)x=-x,putc('-');
			do st[++top]=(x%10)^48,x/=10;
			while(x);
			while(top)putc(st[top--]);
			putc(lst);
		}

		template<class T,class...Types>void operator ()(const T x,const char lst='\n',const Types...args) {
			return (*this)(x,lst),(*this)(args...);
		}

	} O;
	struct Ecat {

		template<class T>void operator ()(const char *fmt,const T x) {
			cerr<<fmt<<':'<<x<<'.'<<endl;
		}

		template<class T,class...Types>void operator ()(const char *fmt,const T x,const Types...args) {
			while(*fmt^',')cerr<<*fmt++;
			return cerr<<':'<<x<<" ,",(*this)(++fmt,args...);
		}

	} E;

} using namespace IOEcat;

int n,m,idx,que,lim;
int a[M],b[M],c[M],dl[N],dr[N],fa[N],ans[N],dep[N],siz[N],son[N],top[N];
struct Change {
	int i,t,op;
};
struct Query {
	int x,id;
};
struct CFS {
	int tot,h[N];
	struct edge {
		int v,nxt;
		edge(int v=0,int nxt=0):v(v),nxt(nxt) {}
	} e[N<<1];
	
	edge &operator [](int i) {
		return e[i];
	}
	
	void Init(int n) {
		tot=-1,RCL(h+1,-1,int,n);
	}
	
	void att(int u,int v) {
		e[++tot]=edge(v,h[u]),h[u]=tot;
	}
	
	void con(int u,int v) {
		att(u,v),att(v,u);
	}
	
} g;
struct BIT {
#define lowbit(i) ((i)&-(i))
	int c[N];
	
	void Plus(int x,int d) {
		if(x>0)for(; x<=n; x+=lowbit(x))c[x]+=d;
	}
	
	int Sum(int x) {
		int ans(0);
		if(x>0)for(; x; x&=x-1)ans+=c[x];
		return ans;
	}
	
	int Sum(int l,int r) {
		return Sum(r)-Sum(l-1);
	}
	
#undef lowbit
} bit;

void dfs0(int u) {
	dep[u]=dep[fa[u]]+1,siz[u]=1,son[u]=0;
	EDGE(g,i,u,v)if(v^fa[u])fa[v]=u,dfs0(v),siz[u]+=siz[v],son[u]=(siz[son[u]]>siz[v]?son[u]:v);
}

void dfs1(int u) {
	dl[u]=++idx;
	if(son[u])top[son[u]]=top[u],dfs1(son[u]);
	EDGE(g,i,u,v)if(v!=fa[u]&&v!=son[u])top[v]=v,dfs1(v);
	dr[u]=idx;
}

int lca(int u,int v) {
	while(top[u]^top[v])dep[top[u]]>dep[top[v]]?u=fa[top[u]]:v=fa[top[v]];
	return dep[u]<dep[v]?u:v;
}

void Plus(int u,int v,int w) {
	int pa(lca(u,v));
	bit.Plus(dl[u],w),bit.Plus(dl[v],w),bit.Plus(dl[pa],-w),bit.Plus(dl[fa[pa]],-w);
}

#define mid ((l+r)>>1)
void GBS(int l,int r,vector<Change> &Cha,vector<Query> &Que) {
	DE(l,r);
	if(Que.empty())return Cha.clear();
	if(l==r) {
		for(const Query &q:Que)ans[q.id]=l;
		return Cha.clear(),Que.clear();
	}
	int it(0),cnt(0);
	vector<Change> Cl,Cr;
	vector<Query> Ql,Qr;
	for(const Query &q:Que) {
		while(it<(int)Cha.size()&&Cha[it].t<q.id) {
			if(c[Cha[it].i]>mid)Plus(a[Cha[it].i],b[Cha[it].i],Cha[it].op),cnt+=Cha[it].op;
			++it;
		}
		(bit.Sum(dl[q.x],dr[q.x])==cnt?Ql:Qr).push_back(q);
	}
	FOR(i,0,it-1)if(c[Cha[i].i]>mid)Plus(a[Cha[i].i],b[Cha[i].i],-Cha[i].op);
	for(const Change &cha:Cha)(c[cha.i]<=mid?Cl:Cr).push_back(cha);
	return Cha.clear(),Que.clear(),GBS(l,mid,Cl,Ql),GBS(mid+1,r,Cr,Qr);
}
#undef mid

int main() {
#ifdef Plus_Cat
	freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
	I(n,m),g.Init(n);
	FOR(i,2,n) {
		int u,v;
		I(u,v),g.con(u,v);
	}
	dfs0(1),top[1]=1,dfs1(1);
	vector<Change> Cha;
	vector<Query> Que;
	FOR(i,1,m) {
		int t;
		I(t);
		if(t==0)I(a[i],b[i],c[i]),Cha.push_back({i,que,1}),tomax(lim,c[i]);
		else if(t==1)I(a[i]),Cha.push_back({a[i],que,-1});
		else I(a[i]),Que.push_back({a[i],++que});
	}
	GBS(-1,lim,Cha,Que);
	FOR(i,1,que)O(ans[i],'\n');
	return 0;
}

posted @ 2025-01-22 10:31  Add_Catalyst  阅读(11)  评论(0)    收藏  举报