洛谷 P4768 [NOI2018]归程

题目:归程&归程+


思路:

1、一种海拔 30’

求最短路。

询问时,海拔==0,输出0;否则输出dist[v]。

2、链 15’

离散化。

预处理出不同海拔、每个点开始到起点的答案,查表输出。

3、树 10

树上倍增。

4、

kruskal重构树+树上倍增。

做kruskal时,在并查集路径压缩时,同时存下树的心态。

即,在最小生成树连边时,新建一个节点,权为边权,作为两节点的父节点。

然后再在重构树上倍增求解。


代码:

#include<bits/stdc++.h>
using namespace std;

#define read(x) scanf("%d",&x)
#define ll long long
#define inf (1LL<<60)

struct Edge{
	int x,y,w,v;
	Edge(){}
	Edge(int xx,int yy,int ww,int vv) {x=xx,y=yy,w=ww,v=vv;}
	bool operator < (const Edge& oth) const {
		return v>oth.v;
	}
};

struct Pair{
	ll x,y;
	Pair(){}
	Pair(ll xx,ll yy) {x=xx,y=yy;}
	bool operator < (const Pair& oth) const {return y>oth.y;}
};

#define maxnall 200000
#define maxmall 400000

int n,m;
int X[maxmall+5],Y[maxmall+5],W[maxmall+5],V[maxmall+5];
int Q,K,S;

#define maxn30 200000
#define maxm30 400000

vector<Edge> g30[maxn30+5];
ll dist[maxn30+5];
bool vis[maxn30+5];
priority_queue<Pair> que,emp;

void MakeClean30() {
	for(int i=1;i<=n;i++) g30[i].clear();
	dist[1]=0;for(int i=2;i<=n;i++) dist[i]=inf;
	memset(vis,0,sizeof(vis));
	que=emp;
}

void dijkstra30() {
	que.push(Pair(1,0));
	while(!que.empty()) {
		int h=que.top().x;que.pop();
		if(vis[h]) continue;vis[h]=true;
		for(int i=0;i<g30[h].size();i++) {
			Edge y=g30[h][i];
			if(dist[y.y]>dist[h]+y.w) {
				dist[y.y]=dist[h]+y.w;
				que.push(Pair(y.y,dist[y.y]));
			}
		}
	}
}

void slv30() {
	for(int i=1;i<=m;i++) {
		g30[X[i]].push_back(Edge(X[i],Y[i],W[i],V[i]));
		g30[Y[i]].push_back(Edge(Y[i],X[i],W[i],V[i]));
	}
	
	dijkstra30();
	
	for(int i=1;i<=Q;i++) {
		int x,v;
		read(x),read(v);
		if(v>=1) printf("%lld\n",dist[x]);
		else printf("0\n");
	}
}

#define maxnlink 1500
#define maxwlink 4000
#define maxQlink 100000

int wlink[maxnlink+5],vlink[maxnlink+5];
int Qn[maxQlink+5],Qv[maxQlink+5];
map<int,int> mplink;int cnt;

ll flink[maxnlink+5][maxwlink+5];
ll slink[maxnlink+5];

void MakeCleanlink() {
	mplink.clear(),cnt=0;
	memset(flink,0,sizeof(flink));
	memset(slink,0,sizeof(slink));
}

void slvlink() {
	for(int i=1;i<n;i++) {
		wlink[Y[i]]=W[i],vlink[Y[i]]=V[i];
		mplink[vlink[Y[i]]]=true;
	}
	for(int i=1;i<=Q;i++) {
		read(Qn[i]),read(Qv[i]);
		mplink[Qv[i]]=true;
	}
	
	for(map<int,int>::iterator it=mplink.begin();it!=mplink.end();++it) {
		mplink[it->first]=++cnt;
	}
	for(int i=2;i<=n;i++) vlink[i]=mplink[vlink[i]];
	for(int i=1;i<=Q;i++) Qv[i]=mplink[Qv[i]];
	
	for(int i=2;i<=n;i++) slink[i]=wlink[i]+slink[i-1];
	for(int d=1;d<=cnt;d++) {
		int lstd=0;
		for(int i=2;i<=n;i++) {
			if(vlink[i]<=d) lstd=i;
			flink[i][d]=slink[lstd];
		}
	}
	
	for(int i=1;i<=Q;i++) {
		printf("%lld\n",flink[Qn[i]][Qv[i]]);
	}
}

#define maxn 200000
#define maxm 800000
#define intinf (1<<30)

struct Node{
	ll d;
	int x,fa;
	int ch1,ch2;
	Node() {}
};

vector<Edge> e;
int c;
Node tr[maxm+5];

int fa[maxm+5];
int find(int x) {
	if(fa[x]) return fa[x]=find(fa[x]);
	else return x;
}

void MakeClean() {
	MakeClean30();
	e.clear(),c=0;
	memset(tr,0,sizeof(tr));
	memset(fa,0,sizeof(fa));
}

int anc[maxm+5][30];

int srch(int x,int u) {
	for(int i=25;i>=0;i--) {
		if(!anc[x][i]) continue;
		if(tr[anc[x][i]].x>u) x=anc[x][i];
	}
	return x;
}

void dfs(int x) {
	anc[x][0]=tr[x].fa;
	for(int i=1;i<=25;i++) {
		anc[x][i]=anc[anc[x][i-1]][i-1];
	}
	if(tr[x].ch1) dfs(tr[x].ch1);
	if(tr[x].ch2) dfs(tr[x].ch2);
}

void slv() {
	for(int i=1;i<=m;i++) e.push_back(Edge(X[i],Y[i],W[i],V[i]));
	sort(e.begin(),e.end());
	
	for(int i=1;i<=m;i++) {
		g30[X[i]].push_back(Edge(X[i],Y[i],W[i],V[i]));
		g30[Y[i]].push_back(Edge(Y[i],X[i],W[i],V[i]));
	}
	dijkstra30();
	
	for(int i=1;i<=n;i++) {tr[++c].x=intinf;tr[c].d=dist[c];} 
	
	for(int i=0;i<e.size();i++) {
		Edge x=e[i];
		int fa1=find(e[i].x),fa2=find(e[i].y);
		if(fa1==fa2) continue;
		tr[++c].x=min(min(tr[fa1].x,tr[fa2].x),x.v);
		tr[c].d=min(tr[fa1].d,tr[fa2].d);
		tr[c].ch1=fa1,tr[c].ch2=fa2;
		tr[fa1].fa=c,tr[fa2].fa=c;
		fa[fa1]=c,fa[fa2]=c;
	}
	
	dfs(c);

	int lst=0;	
	for(int i=1;i<=Q;i++) {
		int x,v;
		read(x),read(v);
		x=(x+K*lst-1)%n+1,v=(v+K*lst)%(S+1);
		int u=srch(x,v);
		printf("%lld\n",lst=tr[u].d);
	}
}

int main() {
	int T;
	read(T);
	while(T--) {
		bool is30=true;
		read(n),read(m);
		for(int i=1;i<=m;i++) {
			read(X[i]),read(Y[i]),read(W[i]),read(V[i]);
			if(V[i]!=1) is30=false;
		}
		read(Q),read(K),read(S);
		
		if(is30) {
			MakeClean30();
			slv30();
		} else if(n<=maxnlink&&m==n-1) {
			MakeCleanlink();
			slvlink();
		} else {
			MakeClean();
			slv();
		}
	}
	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值