【比赛】高一下二调

image

板子题合集。
唯一的难点在于没告诉我们要考试 (悲)
但是 \(AK\) 力 (喜)

T1 交通管制

题面

image

最短路。
正解应该是记录路径,然后将路径上每一条边 \(\times \ 2\) 后跑最短路,统计答案
但可以直接遍历所有的边,统计答案
赛时打的 \(SPFA\) 没被卡,过了 😃

Update:赛后新添了 5 组 Hack 数据,告诉我们有很多重边,不能用堆优化 Dij,所以下面这三个代码都过不了了

感谢 @wwppcc 提供的(现在不是)正解代码

“正解”
#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int N=251;
int n,m,tot,mx[N],ed[N][N],l[N],lf[N],lt[N],tp;
ll dis[N],ans,output;
bool vis[N];
priority_queue <pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
void djs()
{
	q.push({0,1});
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0;
	while(!q.empty())
	{
		int st=q.top().second;
		q.pop();
		if(vis[st])continue;
		vis[st]=1;
		for(int i=1;i<=n;i++)
		{
			if(!vis[i]&&ed[st][i]&&dis[i]>dis[st]+ed[st][i])
			{
				dis[i]=dis[st]+ed[st][i];
				l[i]=st;
				q.push({dis[i],i});
			}
		}
	}ans=dis[n];
}
void find(int x)
{
	if(l[x])
	{
		lf[++tp]=l[x];
		lt[tp]=x;
		find(l[x]);
	}else return;
}
void d(int f,int t)
{
	q.push({0,1});
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	int lst=ed[f][t];
	ed[f][t]*=2;
	ed[t][f]*=2;
	dis[1]=0;
	while(!q.empty())
	{
		int st=q.top().second;
		q.pop();
		if(vis[st])continue;
		vis[st]=1;
		for(int i=1;i<=n;i++)
		{
			if(!vis[i]&&ed[st][i]&&dis[i]>dis[st]+ed[st][i])
			{
				dis[i]=dis[st]+ed[st][i];
				l[i]=st;
				q.push({dis[i],i});
			}
		}
	}
	output=max(output,dis[n]-ans);
	ed[f][t]=lst;
	ed[t][f]=lst;
}
void init()
{
	scanf("%d%d",&n,&m);
	int f,t,w;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&f,&t,&w);
		ed[f][t]=w;
		ed[t][f]=w;
	}djs();
	find(n);
	for(int i=1;i<=tp;i++)
	{
		d(lf[i],lt[i]);
	}printf("%lld",output);
}
int main()
{
	freopen("traffic.in","r",stdin);
	freopen("traffic.out","w",stdout);
	init();
	return 0;
}
SPFA
#include<bits/stdc++.h>
using namespace std;
const int N=255;
struct edge{
	int next,to,w;
}e[250005*2];
int h[N],cnt;
inline void add(int u,int v,int w){
	e[++cnt]={h[u],v,w};
	h[u]=cnt;
}
int n,m,x,y,z;
int dis[N],vis[N];
inline void spfa(int x){
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	queue<int> q;
	dis[x]=0;vis[x]=1;
	q.push(x);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(register int i=h[u];i;i=e[i].next){
			int to=e[i].to;
			if(dis[to]>dis[u]+e[i].w){
				dis[to]=dis[u]+e[i].w;
				if(!vis[to]){
					q.push(to);
					vis[to]=1;
				}
			}
		}
		vis[u]=0;
	}
}
int main(){
	freopen("traffic.in","r",stdin);
	freopen("traffic.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(register int i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);add(y,x,z);
	}
	spfa(1);
	int last=dis[n],ans=0;
	for(register int i=1;i<=m*2;i+=2){
		e[i].w*=2;e[i+1].w*=2;
		spfa(1);
		ans=max(ans,dis[n]);
		e[i].w/=2;e[i+1].w/=2;
	}
	printf("%d",ans-last);
	fclose(stdin);
	fclose(stdout);
	return 0;
}
Dijkstra
#include<bits/stdc++.h>
using namespace std;
const int N=255;
typedef pair<int,int> pii;
struct edge{
	int next,to,w;
}e[250005*2];
int h[N],cnt;
inline void add(int u,int v,int w){
	e[++cnt]={h[u],v,w};
	h[u]=cnt;
}
int n,m,x,y,z;
int dis[N],vis[N];
inline void dij(int x){
	priority_queue<pii,vector<pii>,greater<pii> > p;
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	p.push({0,x});
	dis[x]=0;
	while(!p.empty()){
		int u=p.top().second;
		p.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(int i=h[u];i;i=e[i].next){
			int to=e[i].to;
			if(!vis[to]&&dis[to]>dis[u]+e[i].w){
				dis[to]=dis[u]+e[i].w;
				p.push({dis[to],to});
			}
		}
	}
}
int main(){
	freopen("traffic.in","r",stdin);
	freopen("traffic.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(register int i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);add(y,x,z);
	}
	dij(1);
	int last=dis[n],ans=0;
	for(register int i=1;i<=m*2;i+=2){
		e[i].w*=2;e[i+1].w*=2;
		dij(1);
		ans=max(ans,dis[n]);
		e[i].w/=2;e[i+1].w/=2;
	}
	printf("%d",ans-last);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

感谢 @DHYY 提供的朴素 Dij 过法

正解
#include<bits/stdc++.h>
#define fo(x,y,z) for(int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(int (x)=(y);(x)>=(z);(x)--)
inline int qr()
{
	char ch=getchar();int x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f; 
}
#define qr qr()
using namespace std;
const int Ratio=0;
const int N=3005;
const int maxint=INT_MAX;
int n,m,cnt;
int dh[N][N];
int t1,t2;
int biaoji[N];
bool kkk;
vector<int>v;
namespace work1
{
	bool yz[N];
	int yy[N];
	void sol()
	{
		memset(yy,0x3f,sizeof yy);
		yy[1]=0;
		fo(i,2,n)
		{
			int k=0;
			fo(j,1,n)
				if(yy[j]<yy[k]&&!yz[j])
					k=j;
			yz[k]=true;
			fo(j,1,n)
//				if(!yz[j])
//					yy[j]=min(yy[j],yy[k]+dh[k][j]);
				if(yy[k]+dh[k][j]<yy[j])
				{
					yy[j]=yy[k]+dh[k][j];
					biaoji[j]=k;
				}
		}
//		fo(i,1,n)标记正确已验 
//			cout<<i<<' '<<biaoji[i]<<endl;
		t1=yy[n];
	}//t1正确已验 
	void findmax(int x)
	{
		v.push_back(x);
		if(x==1)
			return;
		findmax(biaoji[x]);
	}
    void pd()
    {
        if(n==3&&m==3&&dh[1][2]==3)
        {
            cout<<2;
            kkk=true;
        }
    }
}
namespace work2
{
	bool yz[N];
	int yy[N];
	void sol()
	{
		memset(yy,0x3f,sizeof yy);
        memset(yz,0,sizeof yz);
		yy[1]=0;
		fo(i,2,n)
		{
			int k=0;
			fo(j,1,n)
				if(yy[j]<yy[k]&&!yz[j])
					k=j;
			yz[k]=true;
			fo(j,1,n)
				if(!yz[j])
					yy[j]=min(yy[j],yy[k]+dh[k][j]);
		}
        // cout<<yy[n]<<endl;
		if(yy[n]!=yy[n+1])
            t2=max(t2,yy[n]);
	}
}
int main()
{
	freopen("traffic.in","r",stdin);
	freopen("traffic.out","w",stdout);
	// freopen("1.in","r",stdin);
    // freopen("1.out","w",stdout);
	n=qr,m=qr;
	memset(dh,0x3f,sizeof dh);
	fo(i,1,m)
	{
		int a=qr,b=qr,c=qr;
		if(!dh[a][b]||c<dh[a][b])
            dh[a][b]=dh[b][a]=c;
	}
	work1::sol();
    // cout<<t1<<endl;
	work1::findmax(n);
	int fla,nnn=-maxint;
	int qi,zhong;
    t2=-maxint;
    work1::pd();
    if(kkk)
        return Ratio;
    // cout<<t2<<endl;
// 	for(auto i:v)
// 	{
// 		if(i==n)
// 		{
// 			fla=i;
// 			continue;
// 		}
// 		if(nnn<dh[i][fla])
// 			qi=i,zhong=fla,nnn=dh[i][fla];
// //		cout<<i<<' '<<fla<<' '<<nnn<<endl;
// 		fla=i;
// 	}
    for(auto i:v)
    {
        // cout<<i<<' '<<fla<<endl;
        if(i==n)
        {
            fla=i;
            continue;
        }
        // if(dh[i][fla]==nnn)
        // {
            // cout<<"{}{"<<endl;
            nnn=dh[i][fla];
            dh[i][fla]*=2;
            dh[fla][i]=dh[i][fla];
            work2::sol();
            dh[i][fla]=dh[fla][i]=nnn;
        // }
        fla=i;
    }
	// work2::sol();
	printf("%d\n",t2-t1);
	
	fclose(stdin);
	fclose(stdout);
	return Ratio;
}

T2 教室安排

题面

image

二分水题。
二分距离,按贪心的思想,距离够了就放。

代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
typedef long long ll;
ll a[N];
int n,m;
bool check(ll x){
	int num=1,now=1;
	for(int i=2;i<=n;i++){
		if(a[i]-a[now]>=x){
			now=i;
			num++;
			if(num>=m)return 1;
		}
	}
	return num>=m;
}
int main(){
	freopen("classroom.in","r",stdin);
	freopen("classroom.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	sort(a+1,a+1+n);
	ll l=1,r=1e9+5,mid;
	while(l<=r){
		mid=(l+r)>>1;
		if(check(mid))l=mid+1;
		else r=mid-1;
	}
	cout<<r;
	fclose(stdin);
	fclose(stdout);
	return 0;
}

T3 招商

题面

image

单调栈板子。
左右扫两次单调栈,求出一个建筑向左右的最大扩展距离,乘上高度即可。

代码
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+5;
typedef long long ll;
ll n,h[N],sum=0;
ll l[N],r[N];
stack<ll> s;
int main(){
	freopen("post.in","r",stdin);
	freopen("post.out","w",stdout);
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&h[i]);
		l[i]=r[i]=1;
	}
	for(int i=1;i<=n;i++){
		while(!s.empty()&&h[s.top()]>=h[i]){
			l[i]=l[i]+l[s.top()];
			s.pop();
		}
		s.push(i);
	}
	while(!s.empty())s.pop();
	for(int i=n;i>=1;i--){
		while(!s.empty()&&h[s.top()]>=h[i]){
			r[i]=r[i]+r[s.top()];
			s.pop();
		}
		s.push(i);
	}
	for(int i=1;i<=n;i++){
		sum=max(sum,h[i]*(l[i]+r[i]-1));
	}
	cout<<sum;
	fclose(stdin);
	fclose(stdout);
	return 0;
}

T4 帝国大会

题面

image

LCA 板子。
dfs 序和 SPFA 预处理 , 然后查找两个数的最近公共祖先 ,\(ans \ = \ dis[x] + dis[y] - 2 \times dis[LCA]\)

代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct edge{
	int next,to,w;
}e[N*2];
int h[N],cnt;
void add(int u,int v,int w){
	e[++cnt]={h[u],v,w};
	h[u]=cnt;
}
int in[N],out[N],dep[N],num,n,m,q,x,y,z;
int f[N][35];
void dfs(int x,int fa){
	in[x]=++num;
	dep[x]=dep[fa]+1;
	f[x][0]=fa;
	for(int i=h[x];i;i=e[i].next){
		int to=e[i].to;
		if(to==fa)continue;
		if(!in[to]){
			dfs(to,x);
		}
	}
	out[x]=num;
}
inline int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	int d=dep[x]-dep[y];
	for(int i=0;i<30;i++){
		if(d&(1<<i))x=f[x][i];
	}
	if(x==y)return x;
	for(int i=29;i>=0;i--){
		if(f[x][i]!=f[y][i]){
			x=f[x][i];
			y=f[y][i];
		}
		if(f[x][0]==f[y][0])break;
	}
	return f[x][0];
}
int dis[N],vis[N];
inline void spfa(int x){
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	queue<int> q;
	dis[x]=0;vis[x]=1;
	q.push(x);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(register int i=h[u];i;i=e[i].next){
			int to=e[i].to;
			if(dis[to]>dis[u]+e[i].w){
				dis[to]=dis[u]+e[i].w;
				if(!vis[to]){
					q.push(to);
					vis[to]=1;
				}
			}
		}
		vis[u]=0;
	}
}
int main(){
	freopen("meeting.in","r",stdin);
	freopen("meeting.out","w",stdout);
	scanf("%d%d",&n,&m);
	lca(n,m);
	if(n==1){
		scanf("%d",&q);
		for(int i=1;i<=q;i++){
			scanf("%d%d",&x,&y);
			printf("0\n");
		}
		return 0;
	}
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);add(y,x,z);
	}
	dfs(1,0);
	for(int j=1;j<30;j++){
		for(int i=1;i<=n;i++){
			f[i][j]=f[f[i][j-1]][j-1];
		}
	}
	spfa(1);
	scanf("%d",&q);
	for(int i=1;i<=q;i++){
		scanf("%d%d",&x,&y);
		int k=lca(x,y);
		if(k==x||k==y){//赛事觉得需要分类,其实不用,直接打下边那句就行
			printf("%d\n",abs(dis[x]-dis[y]));
		}
		else printf("%d\n",dis[x]+dis[y]-2*dis[k]);
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2024-03-30 18:39  萝卜甜了  阅读(38)  评论(2编辑  收藏  举报