省选专练[SCOI2013]摩托车交易[NOIP2013]货车运输

8 篇文章 0 订阅
3 篇文章 0 订阅

经典题。

做一次MST

然后跑LCA

这样的题我做了五个:


交易啊!交易啊!

跑一个最大生成树,然后贪心就好了

来源:某7th sc

代码丑陋。

#include<bits/stdc++.h>
using namespace std;
#define LL "%lld
const int BUF_SIZE = 30;
char buf[BUF_SIZE], *buf_s = buf, *buf_t = buf + 1;
  
#define PTR_NEXT() \
    { \
        buf_s ++; \
        if (buf_s == buf_t) \
        { \
            buf_s = buf; \
            buf_t = buf + fread(buf, 1, BUF_SIZE, stdin); \
        } \
    }
   
#define readint(_n_) \
    { \
        while (*buf_s != '-' && !isdigit(*buf_s)) \
            PTR_NEXT(); \
        bool register _nega_ = false; \
        if (*buf_s == '-') \
        { \
            _nega_ = true; \
            PTR_NEXT(); \
        } \
        int register _x_ = 0; \
        while (isdigit(*buf_s)) \
        { \
            _x_ = _x_ * 10 + *buf_s - '0'; \
            PTR_NEXT(); \
        } \
        if (_nega_) \
            _x_ = -_x_; \
        (_n_) = (_x_); \
    }

const int maxn=300010;
const int maxm=300010;
const long long INF=0x3f3f3f3f3f3f3f3fll;

int n,m,Q,en,value[maxn],order[maxn],s[maxm],e[maxm],z[maxm],f[maxn][20],depth[maxn],q[maxn],fa[maxn],train[maxn];

long long limit[maxn][20],w[maxm];

struct edge
{
	int e;
	long long d;
	edge *next;
}*v[maxn],ed[maxn<<1];

void add_edge(int s,int e,long long d)
{
	en++;
	ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;v[s]->d=d;
}

int getf(int now)
{
	if (fa[now]==now) return now;
	else return fa[now]=getf(fa[now]);
}

bool cmp(int a,int b)
{
	return w[a]>w[b];
}

void bfs(int rt)
{
	depth[rt]=1;
	int front=1,tail=1;
	q[1]=rt;
	for (;front<=tail;)
	{
		int now=q[front++];
		for (edge *e=v[now];e;e=e->next)
			if (!depth[e->e])
			{
				depth[e->e]=depth[now]+1;
				f[e->e][0]=now;
				limit[e->e][0]=e->d;
				int nowp=now,x=0;
				while (f[nowp][x])
				{
					f[e->e][x+1]=f[nowp][x];
					limit[e->e][x+1]=min(limit[e->e][x],limit[nowp][x]);
					nowp=f[nowp][x];
					x++;
				}
				q[++tail]=e->e;
			}
	}
}

long long solve(int p1,int p2)
{
	long long ans=INF;
	if (depth[p1]<depth[p2]) swap(p1,p2);
	int delta=depth[p1]-depth[p2],x=0;
	while (delta)
	{
		if (delta&1)
		{
			ans=min(ans,limit[p1][x]);
			p1=f[p1][x];
		}
		delta>>=1;
		x++;
	}
	x=0;
	while (p1!=p2)
	{
		if (!x || f[p1][x]!=f[p2][x])
		{
			ans=min(ans,min(limit[p1][x],limit[p2][x]));
			p1=f[p1][x];
			p2=f[p2][x];
			x++;
		}
		else x--;
	}
	return ans;
}

int main()
{

	readint(n);
	readint(m);
	readint(Q);
	for (int a=1;a<=n;a++)
	{
		readint(order[a]);
	}
	for (int a=1;a<=n;a++)
	{
		readint(value[a]);
	}
	for (int a=1;a<=m;a++)
	{
		readint(s[a]);
		readint(e[a]);
		readint(w[a]);
	}
	for (int a=1;a<=Q;a++)
	{
		readint(train[a]);
	}
	for (int a=2;a<=Q;a++)
	{
		s[++m]=train[a-1];
		e[m]=train[a];
		w[m]=INF;
	}
	for (int a=1;a<=m;a++)
		z[a]=a;
	sort(z+1,z+m+1,cmp);
	for (int a=1;a<=n;a++)
		fa[a]=a;
	for (int a=1;a<=m;a++)
	{
		int now=z[a];
		if (getf(s[now])!=getf(e[now]))
		{
			fa[getf(s[now])]=getf(e[now]);
			add_edge(s[now],e[now],w[now]);
			add_edge(e[now],s[now],w[now]);
		}
	}
	bfs(1);
	int nowp=order[1];
	long long nowgold;
	if (value[nowp]<0) printf("0\n"),nowgold=0;
	else nowgold=value[nowp];
	for (int a=2;a<=n;a++)
	{
		nowgold=min(nowgold,solve(order[a-1],order[a]));
		nowp=order[a];
		if (value[nowp]>0) nowgold+=value[nowp];
		else
		{
			long long delta=min(nowgold,-(long long)value[nowp]);
			nowgold-=delta;
			printf("%lld\n",delta);
		}
	}
	
	return 0;
}


简单啊!简单啊!

跑一个最大生成树就完了LCA查

这个算法有bug,一条链就卡死了

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
inline void read(int &x){
	x=0;
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
struct Front_star{
	int u,v,w,nxt;
}e[200010],edge[200010];
int cnt=0;
int first[100010]={0};
void add(int u,int v,int w){
	cnt++;
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].w=w;
} 
int edgecnt=0;
void addedge(int u,int v,int w){
	edgecnt++;
	edge[edgecnt].u=u;
	edge[edgecnt].v=v;
	edge[edgecnt].w=w;
	edge[edgecnt].nxt=first[u];
	first[u]=edgecnt;
} 
int n,m,q;
//kruskal
int fa[100010]={0};
int getfa(int x){
	if(fa[x]==x)
		return x;
	return fa[x]=getfa(fa[x]);
} 
bool cmp(Front_star a,Front_star b){
	return a.w<b.w;
}
void kruskal(){
	sort(e+1,e+1+cnt,cmp);
	for(int i=1;i<=n;i++)
		fa[i]=i;
	for(int i=1;i<=cnt;i++){
		int x=getfa(e[i].u);
		int y=getfa(e[i].v);
		if(x!=y){
			fa[x]=y;
			addedge(e[i].u,e[i].v,e[i].w);
			addedge(e[i].v,e[i].u,e[i].w);
		}
	}
}
// LCA
int vis[100010]={0};
int dep[100010]={0};
int p[200010][30]={0};
int dis[100010]={0};
void dfs(int u){
	vis[u]=1;
	for(int i=first[u];i;i=edge[i].nxt){
		int v=edge[i].v;
		if(!vis[v]){
			dep[v]=dep[u]+1;
			p[v][0]=u;
			dis[v]=edge[i].w;
			dfs(v);
		}
	}
} 
void init(){
	for(int j=1;(1<<j)<=n;j++){
		for(int i=1;i<=n;i++){
			p[i][j]=p[p[i][j-1]][j-1];
		}
	}
}
int LCA(int x,int y){
	if(dep[x]<dep[y])
		swap(x,y);
	int i;
	for(i=0;(1<<i)<=dep[x];i++);
	i--;
	for(int j=i;j>=0;j--){
		if(dep[x]-(1<<j)>=dep[y])
			x=p[x][j];
	}
	if(x==y)
		return x;
	for(int j=i;j>=0;j--){
		if(p[x][j]!=p[y][j]){
			x=p[x][j];
			y=p[y][j];
		}
	}
	return p[x][0];
}
int getans(int x,int y){
	int sum=LCA(x,y);
	int a=-1;
	int b=-1;
	for(int i=x;i!=sum;i=p[i][0])
		a=max(a,dis[i]);
	for(int i=y;i!=sum;i=p[i][0])
		b=max(b,dis[i]);
	return max(a,b);
}
int main(){
	read(n);
	read(m);
	for(int i=1;i<=m;i++){
		int u,v,w;
		read(u);
		read(v);
		read(w);
		add(u,v,w);
		add(v,u,w);
	}
	kruskal();
	dep[1]=1;
	p[1][0]=0;
	dfs(1);
	init();
	read(q);
	for(int i=1;i<=q;i++){
		int x,y;
		read(x);
		read(y);
		int ans=getans(x,y);
		printf("%d\n",ans);
	}
}


货车运输:难住不少人的NOIP题。

貌似和简单题完全一个做法。

万恶之源。就是这里我发现bfs丑陋。

然后写了个错误的dfs

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int fa[20000]={0};//kruskalµÄ²¢²é¼¯£¬²¢ÓÃÀ´ÅжÏ-1
struct Node{
	int u,v,w;
}e[100000];
struct Front_star{
	int u,v,w,nxt;
}edge[100000];
int cnt=0;
int first[20000]={0}; 
void addedge(int u,int v,int w){
	cnt++;
	edge[cnt].u=u;
	edge[cnt].v=v;
	edge[cnt].w=w;
	edge[cnt].nxt=first[u];
	first[u]=cnt;
}
int n,m,q;
int tot=0;
void add(int u,int v,int w){
	tot++;
	e[tot].u=u;
	e[tot].v=v;
	e[tot].w=w;
}
//----------×î´óÉú³ÉÊ÷
int getfa(int x){
	if(fa[x]==x){
		return x;
	}
	return fa[x]=getfa(fa[x]); 
} 
void merge(int x,int y){
	int a=getfa(x);
	int b=getfa(y);
	fa[b]=a;
}
bool cmp(Node a,Node b){
	return a.w>b.w;
}
void kruskal(){
	for(int i=1;i<=n;i++)
		fa[i]=i;
	sort(e+1,e+1+tot,cmp);
	for(int i=1;i<=tot;i++){
		int fx=getfa(e[i].u);
		int fy=getfa(e[i].v);
		if(fx==fy)
			continue;
		addedge(fa[fx],fy,e[i].w);
		fa[fy]=fx;
	}
}
//LCA
int ST[20000][20]={0};
int dep[20000]={0};
int dis[20000]={0};
void dfs(int u){
	for(int j=1;j<=14;j++){
			ST[u][j]=ST[ST[u][j-1]][j-1];
	}
	for(int i=first[u];i;i=edge[i].nxt){
		int v=edge[i].v;
		if(ST[u][0]==v)
			continue;
		ST[v][0]=u;
		dis[v]=edge[i].w;
		dep[v]=dep[u]+1;
		dfs(v);
	}
}
int LCA(int x,int y){
	int i,j;
	if(dep[x]<dep[y]){
		swap(x,y);
	}
	int h=dep[x]-dep[y];
//	for(i=1;(1<<i)<=dep[x];i++);
//	i--;
	for(j=14;j>=0;j--){
		if(h&(1<<j))
			x=ST[x][j];
	}
	if(x==y){
		return x;
	}
	if(x!=y){
		for(j=14;j>=0;j--){
			if(ST[x][j]!=ST[y][j]){
				x=ST[x][j];
				y=ST[y][j];
			}
		}
		x=ST[x][0]; 
	}
	return x;
}
int getans(int x,int y){
	int a=0x7fffffff;
	int b=0x7fffffff;
	int sum=LCA(x,y);
//	cout<<sum<<endl;
	for(int i=x;i!=sum;i=ST[i][0]){
		a=min(a,dis[i]);
	}
	for(int i=y;i!=sum;i=ST[i][0]){
		b=min(b,dis[i]);
	}
	return min(a,b);
}
int main(){
	scanf("%d",&n);
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int u;
		int v;
		int w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
	}
	kruskal();
	for(int i=1;i<=n;i++){
		if(getfa(i)==i){
			ST[i][0]=i;
			dfs(i);
		}
	}
	scanf("%d",&q);
	for(int i=1;i<=q;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		if(getfa(x)!=getfa(y)){
			printf("-1\n");
		} 
		else{
			int ans=getans(x,y);
			printf("%d\n",ans);
		}
	}
} 


稍微难一些。

他这个有球员名字。

不只是编号。

所以可以哈希STL。

map查重

这个时候我发现:为什么莫名超时?

发现跳链很SB。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define N 200000
using namespace std;
inline void read(int &sum){
    char ch=getchar(); sum=0;
    while(!(ch>='0'&&ch<='9'))ch=getchar();
    while(ch>='0'&&ch<='9')sum=(sum<<1)+(sum<<3)+ch-48,ch=getchar();
}
map<string,int> name;
int n,m;
int first[N]={0};
int name_cnt=0; 
int cnt=0;// e's
int tot=0;// edge's
struct Front_star{
	   int u,v,w,nxt;
}edge[2*N];
struct Node{
	   int u,v,w;
}e[2*N];
int fa[N]={0};
void add(int u,int v,int w){
	 cnt++;
	 e[cnt].u=u;
	 e[cnt].v=v;
	 e[cnt].w=w;
}
void addedge(int u,int v,int w){
	 tot++;
	 edge[tot].u=u;
	 edge[tot].v=v;
	 edge[tot].w=w;
	 edge[tot].nxt=first[u];
	 first[u]=tot;
}
//--------------
bool cmp(Node a,Node b){
	return a.w<b.w; 
}
int getfa(int x){
	if(fa[x]==x)
	 return x;
    return fa[x]=getfa(fa[x]);
}
void kruskal(){
	for(int i=1;i<=n;i++)
			fa[i]=i;
	sort(e+1,e+1+cnt,cmp);
	for(int i=1;i<=cnt;i++){
			int fx=getfa(e[i].u);
			int fy=getfa(e[i].v);
			if(fx==fy)
	           continue;
            fa[fy]=fx;
            addedge(fa[fx],fy,e[i].w);
	}
}
//-------------
int p[N][30]={0};
int dep[N]={0};
int dis[N]={0};
void dfs(int u){
	for(int i=1;i<=14;i++){
		p[u][i]=p[p[u][i-1]][i-1];
	}
	for(int i=first[u];i;i=edge[i].nxt){
		int v=edge[i].v;
		if(p[u][0]==v)
			continue;
		p[v][0]=u;
		dep[v]=dep[u]+1;
		dis[v]=edge[i].w;
		dfs(v);
	}
}
int LCA(int x,int y){
	int i,j;
	if(dep[x]<dep[y])
		swap(x,y);
	for(i=0;(1<<i)<=dep[x];i++);
		i--;
	for(j=i;j>=0;j--){
		if(dep[x]-(1<<j)>=dep[y])
			x=p[x][j];
	}
	if(x==y)
		return x;
	if(x!=y){
		for(j=i;j>=0;j--){
			if(p[x][j]!=p[y][j]){
				x=p[x][j];
				y=p[y][j];
			}
		}
	}
	return p[x][0];
}
int getans(int x,int y){
	int len=LCA(x,y);
	int a=-0x7fffffff;
	int b=-0x7fffffff;
	for(int i=x;i!=len;i=p[i][0]){
		a=max(a,dis[i]);
	}
	for(int i=y;i!=len;i=p[i][0]){
		b=max(b,dis[i]);
	}
	return max(a,b);
}
int main(){
	read(n);
	read(m);
	for(int i=1;i<=n;i++){
		char ch[10];
		scanf("%s",ch);
		string s(ch);
//		cin>>s;
		name_cnt++;
		name[s]=name_cnt;
	}
	for(int i=1;i<=m;i++){
		char sa[10];
		char sb[10];
		scanf("%s",sa);
		string a(sa);
		scanf("%s",sb);
		string b(sb);
		int w;
//		cin>>a;
//		cin>>b;
		read(w);
		add(name[a],name[b],w);
		add(name[b],name[a],w);
//		cout<<name[s];
	}
	int q=0;
	kruskal();
	for(int i=1;i<=n;i++){
		if(getfa(i)==i){
			p[i][0]=i;
			dfs(i);
		}
	}
	read(q);
	for(int i=1;i<=q;++i){
		char sa[10];
		char sb[10];
		scanf("%s",sa);
		string a(sa);
		scanf("%s",sb);
		string b(sb);
		int ans=0;
		ans=getans(name[a],name[b]);
		printf("%d\n",ans);
	}
}


万恶之源。

可以追溯到的最早的这种题。

但还就是MST完了LCA。

这个是这种题的绝对标准写法。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define N (long long)3e5+10
#define INF (long long)1e18
inline void read(long long &x){
	x=0;
	long long f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-'){
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
struct Front_star{
	long long u,v,w,nxt;
}e[N*2],edge[N*4];
long long n,m,q;
long long list_incoming[N]={0};
long long trade_sum[N]={0};
long long cnt=0;
void add(long long u,long long v,long long w){
	cnt++;
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].w=w;
}
long long ecnt=0;
long long first[N]={0};
void insert(long long u,long long v,long long w){
	ecnt++;
	edge[ecnt].u=u;
	edge[ecnt].v=v;
	edge[ecnt].w=w;
	edge[ecnt].nxt=first[u];
	first[u]=ecnt;
}
bool cmp(Front_star a,Front_star b){
	return a.w>b.w;
}
// KRUSKAL
long long fa[N]={0};
inline long long getfa(long long x){
	if(fa[x]==x){
		return x;
	}
	else{
		return fa[x]=getfa(fa[x]);
	}
}
inline long long link(long long x,long long y){
	long long dx=getfa(x);
	long long dy=getfa(y);
	fa[dx]=dy;
}
void kruskal(){
	long long all=0;
	for(long long i=1;i<=cnt;i++){
		long long u=e[i].u;
		long long v=e[i].v;
//		cout<<"u= "<<u<<" v= "<<v<<endl; 
		if(getfa(u)!=getfa(v)){
			all++;
			link(u,v);
//			cout<<u<<" "<<v<<" "<<e[i].w<<endl;
//			cout<<e[i].w<<endl;
			insert(u,v,e[i].w);
			insert(v,u,e[i].w);
			if(all==n-1)
				break;
		}
	}
}
// LCA
long long f[N][35]={0};
long long st[N][35]={0};
long long dep[N]={0};
void dfs(long long u,long long fa){
//	cout<<u<<" "<<fa<<endl;
	for(long long i=1;(1<<i)<=dep[u];i++){
		f[u][i]=f[f[u][i-1]][i-1];
		st[u][i]=min(st[f[u][i-1]][i-1],st[u][i-1]);
	}
	for(long long i=first[u];i;i=edge[i].nxt){
		long long v=edge[i].v;
		long long w=edge[i].w;
		if(v==fa)
			continue;
		dep[v]=dep[u]+1;
		f[v][0]=u;
		st[v][0]=w;
		dfs(v,u);
	}
}
long long lca(long long x,long long y){
	long long ans=0;
	if(dep[x]<dep[y]){
		swap(x,y);
	}
	ans=INF+10;
	long long t=dep[x]-dep[y];
	for(long long i=0;(1<<i)<=t;i++){
		if(t&(1<<i)){
			ans=min(ans,st[x][i]);
			x=f[x][i];
		}
	}
//	cout<<"x= "<<x<<" "<<y<<endl; 
	if(x==y){
		return ans;
	}
	
	for(long long i=20;i>=0;i--){
		if(f[x][i]!=f[y][i]){
			ans=min(ans,min(st[x][i],st[y][i]));
			x=f[x][i];
			y=f[y][i];
		}
	}
	ans=min(ans,min(st[x][0],st[y][0]));
	return ans;
}
int main(){
	read(n);
	read(m);
	read(q);
	for(long long i=1;i<=n;i++){
		read(list_incoming[i]);
	} 
	for(long long i=1;i<=n;i++){
		read(trade_sum[i]);
	}
	for(long long i=1;i<=m;i++){
		long long u,v,w;
		read(u);
		read(v);
		read(w);
		add(u,v,w);
	}
//	cout<<"hello wolrd"<<endl;
	if(q){
		long long u;
		read(u);
		for(long long i=2;i<=q;i++){
			long long v;
			read(v);
			add(u,v,INF);
		}
	}
	sort(e+1,e+1+cnt,cmp);
	for(long long i=1;i<=n;i++){
		fa[i]=i;
	}
	kruskal();
//	f[1][0]=1;
//	dep[1]=0;
	dfs(list_incoming[1],0);
	long long nowhaving=0;
	if(trade_sum[list_incoming[1]]<0){
		cout<<0<<endl;
//		return 0;
	}
	else{
		nowhaving=trade_sum[list_incoming[1]];
	}
//	for(long long i=1;i<=n;i++){
//		for(long long j=0;j<=2;j++){
//			cout<<st[i][j]<<" ";
//		}
//		cout<<endl;
//	}
//	cout<<lca(1,3);
	for(long long i=1;i<n;i++){
		long long u=list_incoming[i];
		long long v=list_incoming[i+1];
		long long LCA=lca(u,v);
//		cout<<"LCA= "<<LCA<<" "<<u<<" "<<v<<endl;
		nowhaving=min(nowhaving,LCA);
		if(trade_sum[v]>0){
			nowhaving+=trade_sum[v];
		}
		else{
			printf("%lld\n",min(nowhaving,-trade_sum[v]));
			nowhaving=max((long long)0,nowhaving+trade_sum[v]);
		}
	}
	return 0;
}
好了,做了基本一样的五个题,这类问题也算出师了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值