《LGJOJ 8.25》 测试总结

纯菜了,属于是。

中间还咕了很多场总结。。。

\(T1\) 简单游戏

输入:

输出:

\(\color{red}analysis:\)

考试的时候看错题了,寄。

正常做就是直接暴力区间 \(dp\) 就好了

就是正常的博弈论 \(dp\)

其他没什么好说的了,时间复杂度 \(O(n^2)\)

\(PS:\) 挂成了 \(30pts\)

\(PS:\) 没加记忆化都过了, \(gj\) 的数据不做评价。

点击查看代码
#include<bits/stdc++.h>
typedef long long LL;

using namespace std;
const int MAXN=2010;
int T,n;
int f[MAXN][MAXN];
char st[MAXN];
int pd(int x,int y) {
	if(x<y) return 1;
	if(x==y) return 0;
	if(x>y) return 2;
}
void dfs(int opt,int l,int r,int cc) {
	if(l>r) return ;
	if(f[l][r]!=-1) return ; 
	if(!opt) {
		dfs(opt^1,l+1,r,st[l]);
		int u=f[l+1][r];
		dfs(opt^1,l,r-1,st[r]);
		int v=f[l][r-1];
		if(u==1||v==1) f[l][r]=1;
		else if(!u||!v) f[l][r]=0;
		else f[l][r]=2;
	}
	else {
		if(st[l]<cc||st[r]<cc) {
			f[l][r]=2;
			return ;
		}
		else if(st[l]==cc||st[r]==cc) {
			if(l==r) {
				f[l][r]=0;
				return ;
			}
			int u=1,v=1;
			if(st[l]==cc) {
				dfs(opt^1,l+1,r,cc);
				u=f[l+1][r];
			}
			if(st[r]==cc) {
				dfs(opt^1,l,r-1,cc);
				v=f[l][r-1];
			}
			if(u==2||v==2) f[l][r]=2;
			else if(!u||!v) f[l][r]=0;
			else f[l][r]=1;
		}
		else {
			f[l][r]=1;
		}
	}
}
int main () {
	scanf("%d",&T);
	while(T--) {
		scanf("%s",st+1);
		n=strlen(st+1);
		for(int i=1;i<=n;++i) {
			for(int j=1;j<=n;++j) {
				f[i][j]=-1;
			} 
		}
		dfs(0,1,n,0);
		if(f[1][n]==0) puts("Draw");
		if(f[1][n]==1) puts("Alice");
		if(f[1][n]==2) puts("Bob");
	}
	return 0;
}

\(T2\) 内鬼

输入:

输出:

2

\(\color{blue}analysis:\)

首先我们考虑暴力 \(f_{i,j,S}\) 表示两个内鬼分别在 \(i,j\) 位置,抓到 \(S\) 这个集合里人所耗费的最少时间,然后我们可以获得一个 \(O(en^22^8)\) 的优秀解法,可以获得 \(30pts\)

\(if(dis[i][t]\le e[i].time-f_{i,j,S})\) 如果满足这个条件,我们的 \(dp\) 就可以转移,所以我们需要预处理

但是这样还不够,由于 \(t3\) 便秘时间过长,耗费了将近 \(1h\) 没想到怎么做,于是就回来写这题,突然想到两个内鬼可以拆开计算,然后枚举两个内鬼分别抓捕的人的集合,分别拆成 \(f_{x,S'},f_{y,S''}\)

然后具体能不能做到 \(50pts\) 那一档部分分呢,我觉得应该是可以搞到 \(en2^8\) 的,然后拿 \(50pts\)

然后由于如果我们想拿 \(100pts\) ,我们就绝对不能预处理 \(dis\) 数组,我们考虑有没有一种方法,不用预处理 \(dis\) 数组。

这时候宋哥跑过来和我说分层图,然后就恍然大悟了属于是,我们既然不能直接预处理,那么我们就考虑直接跑最短路,然后对于每个不同的集合 \(S\) ,分成一层,至多分成 \(256\) 层,然后对于每层跑一下最短路,对于那些跨越层之间的路径也是照样跑就行了。

时间复杂度 \(O((2^km+2^ke)\log (2^kn))\) 空间复杂度也比较大,一种比较好的优化方法就是先对每层跑好在去跑分层图的边,这样就不用存那么多边的信息。

点击查看代码
#include<bits/stdc++.h>
typedef long long LL;

using namespace std;
const int MAXN=2e4+10,NN=5200000,MM=2560010,inf=1e9;
int T,n,m,k,Q,S;
struct daduoli {
	int f,t,c;
}que[MAXN];
int id(int opt,int x) {
	return opt*n+x;
}
struct ddl {
	int t,c;
	bool pp;
};
vector<ddl> e[NN];
void add(int f,int t,int c,int pp) {
	e[f].push_back((ddl){t,c,pp});
	e[t].push_back((ddl){f,c,pp});
}
void adline(int f,int t,int c,int pp) {
	add(f,t,c,pp);
	add(t,f,c,pp);
}
int dis[MM],sf[MM],res,X[260],Y[260];
void dij(int sta) {
	int R=id((1<<k)-1,n);
	for(int i=1;i<=R;++i) {
		dis[i]=inf;
		sf[i]=0;
	}
	priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
	q.push(make_pair(0,sta));
	dis[sta]=0;
	while(!q.empty()) {
		int u=q.top().second;
		q.pop();
		if(sf[u]) continue;
		sf[u]=1;
		for(auto t:e[u]) {
			if(!t.pp) {
				if(dis[u]+t.c<dis[t.t]) {
					dis[t.t]=dis[u]+t.c;
					q.push(make_pair(dis[t.t],t.t));
				}
			}
			else {
				if(dis[u]<=t.c) {
					if(t.c<dis[t.t]) {
						dis[t.t]=t.c;
						q.push(make_pair(dis[t.t],t.t));
					}
				}
			}
		}
	}
	for(int i=0;i<S;++i) {
		if(!res) X[i]=inf;
		else Y[i]=inf;
		for(int j=1;j<=n;++j) {
			if(!res) {
				X[i]=min(X[i],dis[id(i,j)]);
			}
			else {
				Y[i]=min(Y[i],dis[id(i,j)]);
			}
		}
	}
}
int main () {
	scanf("%d",&T);
	while(T--) {
		scanf("%d%d%d",&n,&m,&k);
		S=(1<<k);
		for(int i=1;i<=m;++i) {
			scanf("%d%d%d",&que[i].f,&que[i].t,&que[i].c);
		}
		for(int i=0;i<S;++i) {
			for(int j=1;j<=m;++j) {
				adline(id(i,que[j].f),id(i,que[j].t),que[j].c,0);
			}
		}
		scanf("%d",&Q);
		for(int i=1;i<=Q;++i) { 
			int x,y,w;
			scanf("%d%d%d",&x,&y,&w);
			for(int j=0;j<S;++j) {
				if(((j>>(x-1))&1)) continue;
				add(id(j,y),id((j|(1<<(x-1))),y),w,1);
			}
		}
		int x,y;
		scanf("%d%d",&x,&y);
		res=0;
		dij(id(0,x));
		res=1;
		dij(id(0,y));
		int ans=inf;
		--S;
		for(int i=0;i<=S;++i) {
			if(X[i]==inf||Y[(S^i)]==inf) continue;
			ans=min(ans,max(X[i],Y[(S^i)]));
		}
		if(ans!=inf) printf("%d\n",ans);
		else printf("-1\n");
		//init
		for(int i=0;i<=S;++i) {
			for(int j=1;j<=n;++j) {
				e[id(i,j)].clear();
			}
		}
	}
	return 0;
}

\(T3\) 序列统计

\(analysis:\)

考试便秘想不出来。

首先对于 \(mex\) 有一个比较经典的操作,就是将每种数都分开来处理,从 \(1\sim m\) 来进行处理。

然后题目问最小的包含 \(1\sim m\) 的最小长度是多少,其实就是问 \(mex=i(i\in(2\sim m+1))\) 的最小的长度

\(dp\ +\) 主席树

\(\%\%\% sktn0089\ wzr\) 大神

由于我们的暴力是枚举一个左端点一直向右扫,我们考虑优化。

\(f_{i,0/1}\) 表示以 \(i\) 为左端点或右端点使得一段序列包含 \(1\sim a_i\) 的最小的序列长度是多少。

然后我们考虑从 \(a_i=1\)\(i\) 开始枚举。

我们只对 \(f_{i,0}\) 讨论,也就是 \(i\) 为左端点进行讨论,因为为右端点也是同理即可。

我们查询 \(mex(a_i,a_{i+1}...a_{i+f_{i,0}-1})\) ,记为 \(v\) ,然后这个区间就可以贡献给 \(ans_{v}\) ,记 \(ans_v\) 为,\(mex\)\(v\) 的最小序列长度。

对于如何求区间 \(mex\) 我们只需要用主席树查询 \(i+f_{i,0}-1\) 这个版本中最小的最后一次被染色的节点在 \(l\) 左边的即可,具体代码会解释。

然后我们找到这段区间右边第一个 \(a[j]=v\) 的,记为 \(R\) ,左边同理,记为 \(L\)

然后我们就更新这些对应的 \(f\) 即可。

不过注意最后的 \(ans\) 要做一个后缀最小值。

因为对于 \(1\ 3\ 2\) ,实际上找不到 \(mex=2\) 的序列,只找得到 \(mex=3\) 的序列,所以 \(ans_3\) 要贡献给 \(ans_2\) ,也就是后缀最小值。

时间复杂度 \(O(n\log n)\) 空间复杂度 \(n\log n\)

点击查看代码
#include<bits/stdc++.h>
typedef long long LL;

using namespace std;
const int MAXN=5e5+10,inf=1e9;
int n,m;
int a[MAXN],f[MAXN][2],ans[MAXN];
vector<int> e[MAXN];
int T[MAXN],tot;
struct daduoli {
	int v,l,r;
}tr[MAXN*20];
int update(int pre,int l,int r,int x,int i) {
	int nw=++tot;
	tr[nw]=tr[pre];
	if(l<r) {
		int mid=(l+r)/2;
		if(x<=mid) tr[nw].l=update(tr[pre].l,l,mid,x,i);
		else tr[nw].r=update(tr[pre].r,mid+1,r,x,i);
		tr[nw].v=min(tr[tr[nw].l].v,tr[tr[nw].r].v);//对于区间中最后出现位置的数找到一个最小值
	}
	else {
		tr[nw].v=i;//更新x最后出现位置
	}
	return nw;
}
int query(int nw,int pre,int l,int r) {
	if(tr[nw].v>=pre) return r+1;
	if(l==r) return l;
	int mid=(l+r)/2;
	if(tr[tr[nw].l].v>=pre) return query(tr[nw].r,pre,mid+1,r);//如果左区间中所有数最后出现位置都在左端点右边,那就找右区间,因为左区间全都合法
	return query(tr[nw].l,pre,l,mid);
}
int main () {
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m+1;++i) ans[i]=inf;
	for(int i=1;i<=n;++i) {
		scanf("%d",&a[i]);
		e[a[i]].push_back(i);
		if(a[i]==1) f[i][0]=f[i][1]=1;
		else f[i][0]=f[i][1]=inf;
		T[i]=update(T[i-1],1,m,a[i],i);
	}
	for(int i=1;i<=m;++i) {
		for(auto t:e[i]) {
			if(f[t][0]<inf) {
				int l=t,r=t+f[t][0]-1;
				int v=query(T[r],l,1,m);
				ans[v]=min(ans[v],f[t][0]);
				auto it=lower_bound(e[v].begin(),e[v].end(),l)-e[v].begin();
				if(it<e[v].size()) f[e[v][it]][1]=min(f[e[v][it]][1],e[v][it]-l+1);
				--it;
				if(it>=0) f[e[v][it]][0]=min(f[e[v][it]][0],r-e[v][it]+1);
			}
			if(f[t][1]<inf) {
				int l=t-f[t][1]+1,r=t;
				int v=query(T[r],l,1,m);
				ans[v]=min(ans[v],f[t][1]);
				auto it=lower_bound(e[v].begin(),e[v].end(),l)-e[v].begin();
				if(it<e[v].size()) f[e[v][it]][1]=min(f[e[v][it]][1],e[v][it]-l+1);
				--it;
				if(it>=0) f[e[v][it]][0]=min(f[e[v][it]][0],r-e[v][it]+1);
			}
		}
	}
	for(int i=m;i>=2;--i) {
		ans[i]=min(ans[i],ans[i+1]);//记得取一下后缀最小值
	}
	for(int i=2;i<=m+1;++i) {
		printf("%d\n",ans[i]);
	}
	return 0;
}

线段树

\(forgiven\) 讲了一下。

大概是我们记录一个数组 \(f_{i,j}\) 表示从 \(i\) 开始,要使得区间 \(mex\)\(j\) 的最小右端点为多少。

假如我们有这样一个序列,有 \(5\) 个数,那么我们有 \(f[1\sim 3][1]=3,f[4\sim 5][1]=5\)

image

image

然后此时我们添加了 \(2\) 之后,我们就要 对每个 \(2\) 进行分段,然后令区间取一个 \(max\)

如何计算贡献呢,对于 \(i\) 来说,贡献其实就是 \(f_{i,j}-i+1\)

我们进行区间取 \(max\) 的时候,我们可以发现 \(f\) 一定是单调递增的,所以我们二分区间中一个中间的点,满足他左边的数都是小于我们区间 \(max\) 的操作值,这样我们区间赋值,就变成了区间推平,而推平之后贡献,一定是区间右端点的贡献最优,我们修改的时候直接用区间右端点计算贡献,然后 \(push\_up\) 上去就好了

时间复杂度 \(O(nlogn)\)

\(T4\) 最短路

套路题了,属于是。

这题分成两步,首先我们如何维护边权,另外我们如何处理连边。

维护边权

可以看这个

主要解决方法是使用主席树 \(+\) 哈希,这样我们就可以在 \(log|V|\) 的时间复杂度里处理出答案,而对于 \(a\) 如何处理,我们就把他拆成 \(\log a\) 位,这样时间复杂度再乘上一个 \(log\) ,不过问题也不大,也就只是两只 \(\log\) 而已。

处理连边

很显然的是可以使用线段树优化建图的方法,但是这样我们就出现了 \(m\log n\) 条边,我们的时间复杂度就会去到 \(log^3\) ,我们考虑一个经典的 \(trick\) ,直接从 \(dij\) 的原理进行优化,就是说一个区间 \(l_1\sim r_1\)\(l_2\sim r_2\) 连边,那么我们一定是选择 \(l_1\sim r_1\) 中最小的一个点来更新,所以我们只需要对第一个入栈的点进行松弛就可以了。

具体实现建一棵入树,不断往父亲节点爬,如果走到当前节点,就把节点上的边给松弛掉,然后 \(clear\) 掉就好了,但是我们还得维护区间取 \(min\)

也就是说我们需要手写一个堆,它能实现以下两个操作:

  • 区间赋值

  • 区间取 \(min\)

然后我们的时间复杂度就可以控制到 \(log^2\) ,但是这时候我们的空间复杂度来到了 \(log^2\)

因为如果将每个 \(a\) 都拆掉,那么会多一个 \(log\)

解决方案是考虑到 \(a\) 是连续的一段,且不会超过 \(loga\) 位,所以其实只会对很小一段的值产生影响,所以我们只需要在 \(loga\) 次修改中不保留中间修改的版本,实际上与只修改一次所增加的节点数是多不了多少的,可以看成 \(log\)

然后这题我们就做完了,但是我调不过去,懒得调了,具体实现差不多就那样。

时间复杂度 \(O(mlogalog|V|)\) 空间复杂度 \(O(|V|log|V|)\)

下面的代码慎重阅读,不知道为什么回收了还是会爆内存,然后还有一些点 \(WA\) ,懒得调了。

点击查看代码
#include<bits/stdc++.h>
typedef long long LL;

using namespace std;
const int MAXN=1e5+100,N=1e5+60,MODD=1e9+7,NN=MAXN*150;
int n,m,S,T,tot;
int pw[N+100];
struct dll {
	int l2,r2,a,b,i;
};
int res;
int sf[MAXN],rt[MAXN];
struct trr {
	int lc[NN],rc[NN],sum[NN],sz[NN];
	LL hs[NN];
	bool pp[NN];
	int bin[NN],cnt;
	void zt(int x,int v) {
		lc[x]=lc[v]; sum[x]=sum[v];
		rc[x]=rc[v]; sz[x]=sz[v]; hs[x]=hs[v];
	}
	void psup(int x) {
		sum[x]=sum[lc[x]]+sum[rc[x]];
		hs[x]=((LL)pw[sz[lc[x]]]*hs[rc[x]]%MODD+hs[lc[x]])%MODD;
		sz[x]=sz[lc[x]]+sz[rc[x]];
	}
	void build(int &x,int l,int r) {
		if(!cnt) x=++tot;
		else x=bin[cnt--];
		sz[x]=r-l+1; hs[x]=0;
		if(l==r) return ;
		int mid=(l+r)/2;
		build(lc[x],l,mid);
		build(rc[x],mid+1,r);
		psup(x);
	}
	void insert(int &x,int u,int l,int r,int w) {
		if(!cnt) x=++tot;
		else {
			x=bin[cnt--];
			pp[x]=0;
		}
		zt(x,u);
		if(l==r) {
			++hs[x];
			++sum[x];
			return ;
		}
		int mid=(l+r)/2;
		if(w<=mid) insert(lc[x],lc[u],l,mid,w);
		if(w>mid) insert(rc[x],rc[u],mid+1,r,w);
		psup(x);
	}
	void update(int &x,int u,int ori,int l,int r,int L,int R) {
		if(l>=L&&r<=R) {
			x=ori;
			return ;
		}
		if(!cnt) x=++tot;
		else x=bin[cnt--],pp[x]=0;
		zt(x,u);
		int mid=(l+r)/2;
		if(L<=mid) update(lc[x],lc[u],lc[ori],l,mid,L,R);
		if(R>mid) update(rc[x],rc[u],rc[ori],mid+1,r,L,R);
		psup(x);
	}
	int query(int x,int l,int r,int L,int R) {
		if(l>R||r<L) return 0;
		if(l>=L&&r<=R) return sum[x];
		int mid=(l+r)/2;
		return (query(lc[x],l,mid,L,R)+query(rc[x],mid+1,r,L,R));
	}
	int QUERY(int x,int l,int r,int p,int num) {
		if(l==r) return l;
		int mid=(l+r)/2;
		if(sum[lc[x]]>=mid-p+1+num) return QUERY(rc[x],mid+1,r,p,num-sum[lc[x]]);
		return QUERY(lc[x],l,mid,p,num);
	}
	void cop(int &x,int y,int l,int r) {
		if(x==y) return ;
		int ux=x;
		if(!cnt) x=++tot;
		else x=bin[cnt--],pp[x]=0;
		zt(x,ux);
		if(l==r) {
			sz[x]=sz[y]; hs[x]=hs[y]; sum[x]=sum[y];
			return ;
		}
		int mid=(l+r)/2;
		cop(lc[x],lc[y],l,mid);
		cop(rc[x],rc[y],mid+1,r);
		sz[x]=sz[y]; hs[x]=hs[y]; sum[x]=sum[y];
		psup(x);
	}
	void mdf(int &x,int lst,int w,int st) {
		int asd=tot,y=lst;
		while(w) {
			if(w&1) {
				int c=(st>0?query(lst,0,N,0,st-1):0);
				int y=QUERY(lst,0,N,st,c);
				if(y>st) update(x,lst,rt[0],0,N,st,y-1);
				else x=lst;
				insert(x,x,0,N,y);
				lst=x;
			}
			++st;
			w/=2;
		}
		int R=tot; 
		cop(y,x,0,N); x=y;
		for(int j=asd+1;j<=R;++j) {
			bin[++cnt]=j;
			sz[j]=0;
		}
	}
	bool cmp(int a,int b,int l,int r) {
		if(l==r) return sum[a]>sum[b];
		int mid=(l+r)/2;
		if(hs[rc[a]]==hs[rc[b]]) return cmp(lc[a],lc[b],l,mid);
		return cmp(rc[a],rc[b],mid+1,r);
	}
} T1;

struct segment_tree {
	int id[MAXN*4];
	vector<dll> e[MAXN*4];
	void build(int node,int l,int r) {
		if(l==r) {
			id[l]=node;
			return ;
		}
		int mid=(l+r)/2;
		build((node<<1),l,mid);
		build((node<<1|1),mid+1,r);
	}
	void update(int node,int l,int r,int x,int y,int a,int b,int c,int d,int i) {
		if(l>y||r<x) return ;
		if(l>=x&&r<=y) {
			e[node].push_back((dll){a,b,c,d,i});
			return ;
		}
		int mid=(l+r)/2;
		update((node<<1),l,mid,x,y,a,b,c,d,i);
		update((node<<1|1),mid+1,r,x,y,a,b,c,d,i);
	}
}T2;
struct sbtree {
	int x[MAXN*4],lb[MAXN*4],y[MAXN*4];
	bool ta[MAXN*4];
	void psup(int node) {
		if(x[(node<<1)]==-1) {
			x[node]=x[(node<<1|1)];
			y[node]=y[(node<<1|1)];
			return ;
		}
		if(x[(node<<1|1)]==-1) {
			x[node]=x[(node<<1)];
			y[node]=y[(node<<1)];
			return ;
		}
		if(T1.cmp(x[(node<<1|1)],x[(node<<1)],0,N)) {
			x[node]=x[(node<<1)];
			y[node]=y[(node<<1)];
		}
		else {
			x[node]=x[(node<<1|1)];
			y[node]=y[(node<<1|1)];
		}
		if(ta[(node<<1)]&&ta[(node<<1|1)]) ta[node]=1;
	}
	void psdn(int node) {
		if(lb[node]!=-1) {
			int lc=(node<<1),rc=(node<<1|1);
			if(!ta[lc]) {
				if(x[lc]==-1||T1.cmp(x[lc],lb[node],0,N)) x[lc]=lb[node];
				if(lb[lc]==-1||T1.cmp(lb[lc],lb[node],0,N)) lb[lc]=lb[node];
			}
			
			if(!ta[rc]) {
				if(x[rc]==-1||T1.cmp(x[rc],lb[node],0,N)) x[rc]=lb[node];
				if(lb[rc]==-1||T1.cmp(lb[rc],lb[node],0,N)) lb[rc]=lb[node];
			}
			lb[node]=-1;
		}
	}
	void build(int node,int l,int r) {
		lb[node]=-1;
		if(l==r) {
			x[node]=-1;
			y[node]=l;
			return ;
		}
		int mid=(l+r)/2;
		build((node<<1),l,mid);
		build((node<<1|1),mid+1,r);
		psup(node);
	}
	void dele(int node,int l,int r,int X) {
		if(l>X||r<X) return ;
		if(l==r) {
			ta[node]=1;
			x[node]=-1; y[node]=-1;
			return ;
		}
		int mid=(l+r)/2;
		psdn(node);
		dele((node<<1),l,mid,X);
		dele((node<<1|1),mid+1,r,X);
		psup(node);
	}
	void update(int node,int l,int r,int X,int Y,int Z) {
		if(l>Y||r<X) return ;
		if(l>=X&&r<=Y) {
			if(ta[node]) return ;
			if(x[node]==-1||T1.cmp(x[node],Z,0,N)) {
				x[node]=Z;
				lb[node]=Z;
			}
			else if(lb[node]==-1||T1.cmp(lb[node],Z,0,N)) {
				lb[node]=Z;
			}
			return ;
		}
		int mid=(l+r)/2;
		update((node<<1),l,mid,X,Y,Z);
		update((node<<1|1),mid+1,r,X,Y,Z);
		psup(node);
	}
}T3;
bool vis[MAXN];
void init() {
	pw[0]=1;
	for(int i=1;i<=N;++i) pw[i]=pw[i-1]*2%MODD;
	scanf("%d%d",&n,&m);
	T2.build(1,1,n);
	for(int i=1;i<=m;++i) {
		int l1,r1,l2,r2,a,b;
		scanf("%d%d%d%d%d%d",&l1,&r1,&l2,&r2,&a,&b);
		T2.update(1,1,n,l1,r1,l2,r2,a,b,i);
	}
}
void dij() {
	S=1;
	T3.build(1,1,n);
	T1.build(rt[0],0,N); rt[S]=rt[0]; 
	T3.update(1,1,n,S,S,rt[S]);
	while(1) {
		if(T3.y[1]==-1||T3.x[1]==-1) break;
		int u=T3.y[1]; rt[u]=T3.x[1];
		T3.dele(1,1,n,u);
		for(int i=T2.id[u];i;i>>=1) {
			for(auto t:T2.e[i]) {
				if(vis[t.i]) continue;
				vis[t.i]=1;
				T1.mdf(rt[n+1],rt[u],t.a,t.b);
				res=0;
				T3.update(1,1,n,t.l2,t.r2,rt[n+1]);
			}
			T2.e[i].clear();
		}
	}
	for(int i=2;i<=n;++i) {
		if(rt[i]) printf("%lld ",T1.hs[rt[i]]);
		else printf("-1 ");
	}
}
int main () {
	freopen("sb.in","r",stdin);
	freopen("1.out","w",stdout);
	init();
	dij();
	return 0;
}
/*
5 3
1 3 1 3 1 0
4 5 1 2 4 1
2 4 1 5 5 1
*/
posted @ 2023-08-25 16:39  daduoli  阅读(116)  评论(0)    收藏  举报