zoukankan      html  css  js  c++  java
  • 【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构造树

    • 首先得先学这个东东;可以按照(kruskal)(MST)的思想来建出一个无向图的(kruskal)构造树

    • 具体就是按边长度排序后,若边((x,y))(x,y)不连通,建一个新点,新点点权设为边权,把两个集合连到新点上

    • 若边升序排序,则对于((u,v))两点,(LCA(u,v))点权即为原图中(u)(v)所有路径中最大边权的最小值

    • 降序排序则是最小边权的最大值;还有一些有意思的性质,比如构造树是二叉树、大(小)根堆


    analysis

    • 对于点(x)需要知道(x)可以走到的点都有哪些,若建出海拔的(kruskal)构造树,深度越浅点权越小,就是海拔越小

    • 找到构造树中深度最浅且满足海拔恰好(>p)的某个点,那该点的子树中所有点都可以开车互相可达

    • 找这个点可以倍增,由于这些点都可达且剩下没有点可以不下车到达,答案即为该点的子树中到(1)的距离的最小值

    • (1)到每个点的距离用(dij)就好了


    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
    ",lastans=mn[v]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Java入门 第二季第三章 继承
    湖南长沙IOS(xcode swift) 开发交流群
    C++对象模型——&quot;无继承&quot;情况下的对象构造(第五章)
    算术与逻辑运算指令具体解释
    linux中man手冊的高级使用方法
    Swift 数组
    webservice Connection timed out
    创建SharePoint 2010 Timer Job
    指向函数的指针数组的使用方法
    修改Tomcat Connector运行模式,优化Tomcat运行性能
  • 原文地址:https://www.cnblogs.com/horizonwd/p/12064018.html
Copyright © 2011-2022 走看看