noi 2018 归程

对我这种蒟蒻来说,调了好久好久;

  1. 先跑dijkstra,求出1号点到所有点的距离。因为是无向图,其实也就是求了所有点到1号点的距离; 
  2. 第二就是kruskal重构树,说起来就是kruskal加边的时候建立一个新 的点,点权就是这条边的边权,就是如图所示;
  3. 这样有一个好处就是你往上走的时候,经过的点权就是你经过的路径的最大值(可以自行画图看看,我的图巨丑);这样的话你往上走的时候如果需要设置一个最大值,就这样走就好了;
  4. 然后我们发现时间复杂度凉凉了,所以倍增一波;
  5. 最后我们统计答案,就是由于重构树中dfs序是连续的,我们进行st表维护区间最小值!!!

代码巨丑陋。。。 

#include<bits/stdc++.h>
using namespace std;
typedef pair< int,int > pii;

const int inf=2e9;

const int N=700010;

struct zmk{
	int u,v,l,a;
}a[N*3];

struct hyq{
	int next,to,va;
}e[N*2];

int head[N],cnt,fa[N],vis[N],lg[N],cas,f[N][21],h[N][21],tot;
int val[N],st[N],b[N],en[N],d[N],root;

int n,m,q,k;
int find(int u){
	if(fa[u]==u) return fa[u];
	return fa[u]=find(fa[u]);
}
void addedge(int u,int v,int d){
	e[++cnt].next=head[u];
	e[cnt].to=v;
	e[cnt].va=d;
	head[u]=cnt;
}
bool cmp(zmk a,zmk b){
	return a.a>b.a;
}
void dijkstra(){
	d[1]=0;
	priority_queue< pii,vector<pii>,greater<pii> > q;
	q.push(make_pair(d[1],1));
	while(!q.empty()){
		int u=q.top().second;
		q.pop();
		if(vis[u]) continue;
		vis[u]=1;
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;
			if(d[v]>d[u]+e[i].va){
				d[v]=d[u]+e[i].va;
				q.push(make_pair(d[v],v));
			}
		}
	}	
}
void kruskal(){
	
	for(int i=1;i<=m;i++){
		val[i+n]=a[i].a;
		int sa=find(a[i].u),sb=find(a[i].v);
		if(sa!=sb){
			addedge(i+n,sa,0);
			addedge(i+n,sb,0);
			fa[sa]=i+n;
			fa[sb]=i+n;
		}
	}
}
void dfs(int u){
	st[u]=++tot;
	b[tot]=u;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		f[v][0]=u;
		dfs(v);
	}
	en[u]=tot;
}
void init(){	
	f[root][0]=0;
	for(int j=1;j<=20;j++)
	  for(int i=1;i<=n+m;i++){
	  	f[i][j]=f[f[i][j-1]][j-1];
	  	
	  }
	for(int i=1;i<=tot;i++){
	  	if(b[i]<=n) h[i][0]=d[b[i]];
	  	else h[i][0]=inf;	  	
	  }
	for(int j=1;j<=20;j++)
	  for(int i=1;i<=tot-(1<<j)+1;i++){
	  	h[i][j]=min(h[i][j-1],h[i+(1<<(j-1))][j-1]);
		  //cout<<h[i][j]<<" ";
	  }
}
int query(int l,int r){
	int t=lg[r-l+1];
	return min(h[l][t],h[r-(1<<t)+1][t]);
}
int main(){
	for (int i = 2; i < 700000; i++)
		lg[i] = lg[i >> 1] + 1;
	scanf("%d",&cas);
	while(cas--){
		tot=cnt=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++) head[i]=0;
		for(int i=1;i<=m;i++){
			scanf("%d%d%d%d",&a[i].u,&a[i].v,&a[i].l,&a[i].a);
			addedge(a[i].u,a[i].v,a[i].l);
			addedge(a[i].v,a[i].u,a[i].l);
		}
		for(int i=1;i<=n;i++){
			d[i]=inf;
			vis[i]=0;
		}
		dijkstra();
		cnt=0;
		for(int i=1;i<=n+m;i++) head[i]=0;
		sort(a+1,a+m+1,cmp);
		for(int i=1;i<=n+m;i++) fa[i]=i;
		for(int i=1;i<=n;i++) val[i]=inf;
		kruskal();
		root=find(1);
		dfs(root);
		//for(int i=1;i<=tot;i++) cout<<st[i]<<" "<<en[i]<<"***"<<endl;
		init();
		int smax;
		scanf("%d%d%d",&q,&k,&smax);
		int ans = 0;
		while(q--){
			int v , p;
			scanf("%d%d",&v,&p);
			if(k){
				v=(v+ans-1)%n+1;
				p=((long long)p+ans)%(smax+1);
			}
			for(int i=20;i>=0;i--){
				if(val[f[v][i]]>p){
					v=f[v][i];
				}
			}
			printf("%d\n",ans=query(st[v],en[v]));
		}
	}
}

代码很长还没什么用 

猜你喜欢

转载自blog.csdn.net/weixin_42759194/article/details/81812084