LOJ #2718. 「NOI2018」归程 Dijkstra+可持久化并查集

把 $Noi2018$ day1t1 想出来还是挺开心的,虽然是一道水题~
预处理出来 1 号点到其它点的最短路,然后预处理边权从大到小排序后加入前 $i$ 个边的并查集.
这个并查集用可持久化线段树维护可持久化数组来完成.
每次询问时在边集上二分一下,找到对应的并查集,然后找到祖先并输出极小值即可.

#include <bits/stdc++.h> 
#define N 400005  
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)   
using namespace std; 
int n,m,rt[N];   
struct Edge {
	int u,v,l,a; 
}e[N]; 
bool cmp(Edge a,Edge b) {
	return a.a>b.a; 
} 
namespace Dijkstra {    
    struct Node {
    	int u; 
    	ll dis;    
    	Node(int u=0,ll dis=0):u(u),dis(dis){}  
    	bool operator<(Node a)const {
    		return a.dis<dis; 
    	}
    }; 
    priority_queue<Node>q; 
	int edges,s; 
	ll dis[N]; 
	int hd[N],nex[N<<1],val[N<<1],to[N<<1],done[N]; 
	void addedge(int u,int v,int c) {  
		nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; 
	}  
	void re() {  
		edges=0; 
		memset(hd,0,sizeof(hd));   
		memset(dis,0,sizeof(dis)); 
		memset(done,0,sizeof(done)); 
	}
	void solve() {   
		memset(dis,0x3f,sizeof(dis));     
		dis[s]=0; 
		q.push(Node(s,0));   
		while(!q.empty()) {
			Node e=q.top();q.pop(); 
			if(done[e.u]) continue;  
			done[e.u]=1;       
			for(int i=hd[e.u];i;i=nex[i]) 
				if(dis[to[i]]>dis[e.u]+val[i]) { 
					dis[to[i]]=dis[e.u]+val[i]; 
					q.push(Node(to[i], dis[to[i]]));    
				}
		}
	}  
};  
namespace ufs {  
	#define ls t[now].lson
	#define rs t[now].rson    
	struct Node {
		ll min;   
		int fa,size,lson,rson;  
	}t[N*50];              
	int tot;         
	void build(int &now,int l,int r) {   
		now=++tot; 
		if(l==r) {
			t[now].fa=l; 
			t[now].size=1; 
			t[now].min=Dijkstra::dis[l]; 
			return; 
		} 
		int mid=(l+r)>>1; 
		if(l<=mid) build(ls,l,mid); 
		if(r>mid)  build(rs,mid+1,r);        
	} 
	void update(int pre,int &now,int l,int r,int p,Node e) { 
		now=++tot;    
		t[now]=t[pre];        
		if(l==r) { 
			t[now].size=e.size; 
			t[now].fa=e.fa; 
			t[now].min=e.min; 
			return; 
		} 
		int mid=(l+r)>>1;   
		if(p<=mid) update(t[pre].lson,t[now].lson,l,mid,p,e); 
		else update(t[pre].rson,t[now].rson,mid+1,r,p,e);      
	}
	Node query(int now,int l,int r,int p) {
		if(l==r) return t[now];   
		int mid=(l+r)>>1; 
		if(p<=mid) return query(ls,l,mid,p); 
		else return query(rs,mid+1,r,p);  
	}
	Node find(int id,int x) {
	    Node p=query(rt[id],1,n,x);         
	    return p.fa==x?p:find(id,p.fa);    		
	}    
	void merge(int id,int x,int y) {   
		Node a=find(id,x),b=find(id,y); 
		if(a.fa!=b.fa) {
			if(a.size<b.size) swap(a,b);    
			int rt1=0,rt2=0,A=a.fa,B=b.fa;   
			a.size+=b.size;
			a.min=min(a.min,b.min);      
			a.fa=b.fa=A;        
			update(rt[id], rt1, 1, n, A, a);     
			update(rt1, rt2, 1, n, B, b);      
			rt[id+1]=rt2;            
		}    
		else rt[id+1]=rt[id]; 
	} 
	void re() {
		for(int i=1;i<=tot;++i) t[i].lson=t[i].rson=t[i].size=t[i].min=t[i].fa=0; 
		tot=0; 
	}
	#undef ls 
	#undef rs 
}; 
void work() {  
	int i;  
	scanf("%d%d",&n,&m);  
	for(i=1;i<=m;++i) {
		scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].l,&e[i].a); 
		Dijkstra::addedge(e[i].u,e[i].v,e[i].l); 
		Dijkstra::addedge(e[i].v,e[i].u,e[i].l);   
	}
	Dijkstra::s=1; 
	Dijkstra::solve(); 
	sort(e+1,e+1+m,cmp);      
	ufs::build(rt[0],1,n); 
	for(i=1;i<=m;++i) ufs::merge(i-1,e[i].u,e[i].v);              
	ll lastans=0; 
	int Q,K,S; 
    scanf("%d%d%d",&Q,&K,&S);       
    for(i=1;i<=Q;++i) {
    	int v,p; 
    	scanf("%d%d",&v,&p);     
    	v=(v+K*lastans-1)%n+1;         
    	p=(p+K*lastans)%(S+1); 
    	if(e[m].a>p) printf("0\n"),lastans=0; 
    	else {
    		int l=0,r=m,mid=0,ans=0; 
    		while(l<=r) { 
    			mid=(l+r)>>1;    
    			if(e[mid].a>p) { 
    				ans=mid,l=mid+1; 
    			}
    			else r=mid-1;    
    		}   
    		ufs::Node e=ufs::find(ans,v);       
    		printf("%lld\n",lastans=e.min);     
    	}
    }      
    memset(rt,0,sizeof(rt));   
    Dijkstra::re(); 
    ufs::re();   
}
int main() { 
	// setIO("input"); 
	int T,i; 
	scanf("%d",&T); 
	for(i=1;i<=T;++i) work(); 
	return 0; 
}

  

posted @ 2019-08-29 07:51  EM-LGH  阅读(134)  评论(0编辑  收藏  举报