【luoguP4768】【NOI2018】歸程

description

本題的故事發生在魔力之都,在這裏我們將爲你介紹一些必要的設定。 魔力之都可以抽象成一個 nn 個節點、mm 條邊的無向連通圖(節點的編號從 11 至 nn)。我們依次用 l,al,a 描述一條邊的長度、海拔。 作爲季風氣候的代表城市,魔力之都時常有雨水相伴,因此道路積水總是不可避免 的。由於整個城市的排水系統連通,因此有積水的邊一定是海拔相對最低的一些邊。我們用水位線來描述降雨的程度,它的意義是:所有海拔不超過水位線的邊都是有積水的。

Yazid 是一名來自魔力之都的OIer,剛參加完ION2018 的他將踏上歸程,回到他 溫暖的家。 Yazid 的家恰好在魔力之都的 11 號節點。對於接下來 QQ 天,每一天Yazid 都會告訴你他的出發點 vv ,以及當天的水位線pp。 每一天,Yazid 在出發點都擁有一輛車。這輛車由於一些故障不能經過有積水的邊。 Yazid 可以在任意節點下車,這樣接下來他就可以步行經過有積水的邊。但車會被留在他下車的節點並不會再被使用。 需要特殊說明的是,第二天車會被重置,這意味着:

車會在新的出發點被準備好。
Yazid 不能利用之前在某處停放的車。
Yazid 非常討厭在雨天步行,因此他希望在完成回家這一目標的同時,最小化他步行經過的邊的總長度。請你幫助 Yazid 進行計算。 本題的部分測試點將強制在線,具體細節請見【輸入格式】和【子任務】。


kruskal構造樹

  • 首先得先學這個東東;可以按照kruskalkruskalMSTMST的思想來建出一個無向圖的kruskalkruskal構造樹

  • 具體就是按邊長度排序後,若邊(x,y)(x,y)x,yx,y不連通,建一個新點,新點點權設爲邊權,把兩個集合連到新點上

  • 若邊升序排序,則對於(u,v)(u,v)兩點,LCA(u,v)LCA(u,v)點權即爲原圖中uuvv所有路徑中最大邊權的最小值

  • 降序排序則是最小邊權的最大值;還有一些有意思的性質,比如構造樹是二叉樹、大(小)根堆


analysis

  • 對於點xx需要知道xx可以走到的點都有哪些,若建出海拔的kruskalkruskal構造樹,深度越淺點權越小,就是海拔越小

  • 找到構造樹中深度最淺且滿足海拔恰好>p>p的某個點,那該點的子樹中所有點都可以開車互相可達

  • 找這個點可以倍增,由於這些點都可達且剩下沒有點可以不下車到達,答案即爲該點的子樹中到11的距離的最小值

  • 11到每個點的距離用dijdij就好了


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#define MAXN 400005
#define MAXM 400005
#define reg register int
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define rep(i,a) for (reg i=las[a];i;i=nex[i])

using namespace std;

int las[MAXM*2],nex[MAXM*2],tov[MAXM*2],len[MAXM*2];
int fa[MAXN],dis[MAXN],val[MAXN],mn[MAXN];
int n,m,q,k,s,T,tot,cnt,lastans;
int anc[MAXN][20];
bool bz[MAXN];

struct edge
{
	int x,y,len,height;
}f[MAXM];

struct node
{
	int x,y;
	bool operator<(const node &a)const{return a.y<y;}
};
priority_queue<node>que;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
inline int max(int x,int y){return x>y?x:y;}
inline int min(int x,int y){return x<y?x:y;}
inline bool cmp(edge a,edge b){return a.height>b.height;}
inline int getfa(int x){return fa[x]==x?x:fa[x]=getfa(fa[x]);}
inline void link(int x,int y){nex[++tot]=las[x],las[x]=tot,tov[tot]=y;}
inline void linkk(int x,int y,int z){nex[++tot]=las[x],las[x]=tot,tov[tot]=y,len[tot]=z;}
inline void dfs(int x)
{
	mn[x]=dis[x];
	rep(i,x)anc[tov[i]][0]=x,dfs(tov[i]),mn[x]=min(mn[x],mn[tov[i]]);
}
inline void build()
{
	fo(i,1,n)fa[i]=i;sort(f+1,f+m+1,cmp);

	fo(i,1,m)
	{
		int fx=getfa(f[i].x),fy=getfa(f[i].y);
		if (fx!=fy)
		{
			val[++cnt]=f[i].height;
			fa[cnt]=fa[fx]=fa[fy]=cnt;
			link(cnt,fx),link(cnt,fy);
		}
	}
	dfs(cnt);
}
inline void dijkstra()
{
	memset(bz,1,sizeof(bz));
	memset(dis,100,sizeof(dis));
	que.push((node){1,dis[1]=0});

	while (!que.empty())
	{
		node now=que.top();que.pop();
		if (!bz[now.x])continue;bz[now.x]=0;
		rep(i,now.x)if (dis[now.x]+len[i]<dis[tov[i]])
		{
			dis[tov[i]]=dis[now.x]+len[i];
			if (bz[tov[i]])que.push((node){tov[i],dis[tov[i]]});
		}
	}
}
int main()
{
	//freopen("P4768.in","r",stdin);
	T=read();
	while (T--)
	{
		memset(las,0,sizeof(las)),memset(nex,0,sizeof(nex)),
		memset(nex,0,sizeof(nex)),memset(len,0,sizeof(len)),tot=lastans=0;

		n=cnt=read(),m=read();
		fo(i,1,m)f[i].x=read(),f[i].y=read(),f[i].len=read(),f[i].height=read(),
			linkk(f[i].x,f[i].y,f[i].len),linkk(f[i].y,f[i].x,f[i].len);

		dijkstra();
		memset(las,0,sizeof(las)),memset(nex,0,sizeof(nex)),
		memset(nex,0,sizeof(nex)),memset(len,0,sizeof(len)),tot=0;
		memset(mn,100,sizeof(mn));

		build(),q=read(),k=read(),s=read();

		int log=(int)log2(cnt);
		fo(j,1,log)fo(i,1,cnt)anc[i][j]=anc[anc[i][j-1]][j-1];

		fo(i,1,q)
		{
			int v=(read()+k*lastans-1)%n+1,p=(read()+k*lastans)%(s+1);
			fd(j,19,0)if (anc[v][j] && val[anc[v][j]]>p)v=anc[v][j];
			printf("%d\n",lastans=mn[v]);
		}
	}
	return 0;
}
發佈了372 篇原創文章 · 獲贊 305 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章