题解 CF938G 【Shortest Path Queries】

题目让我们维护一个连通无向图,边有边权,支持加边删边和询问从\(x\)到\(y\)的异或最短路。

考虑到有删边这样的撤销操作,那么用线段树分治来实现,用线段树来维护询问的时间轴。

将每一条边的出现时间段标记到线段树上,表示在这一段询问中这条边存在。

异或最短路的处理方法与最大XOR和路径类似,给线段树上每个节点开一个线性基,找出当前所有的环,插入该节点的线性基,查询时任意找出一条从\(x\)到\(y\)的路径,到线性基中查询,即为答案。

具体实现时用可撤销并查集,采用按秩合并来优化,因为路径压缩会破坏树的结构。

具体实现细节看代码吧。

\(code:\)

#include<bits/stdc++.h>
#define maxn 400010
using namespace std;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,m,q,num,tree_cnt,edge_cnt,root,top;
int ls[maxn],rs[maxn],pre[maxn],nxt[maxn],ans[maxn];
map<pair<int,int>,int> mp;
struct Edge
{
    int x,y,v;
}e[maxn];
struct node
{
    int x,y,deep;
}st[maxn];
struct query
{
    int x,y;
}qu[maxn];
void build(int l,int r,int &cur)
{
    if(!cur) cur=++tree_cnt;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(l,mid,ls[cur]);
    build(mid+1,r,rs[cur]);
}
vector<int> v[maxn];
void insert(int L,int R,int l,int r,int id,int cur)
{
    if(L<=l&&R>=r)
    {
        v[cur].push_back(id);
        return;
    }
    int mid=(l+r)>>1;
    if(L<=mid) insert(L,R,l,mid,id,ls[cur]);
    if(R>mid) insert(L,R,mid+1,r,id,rs[cur]);
}
int a[maxn][40];
void ins(int x,int cur)
{
    for(int i=30;i>=0;--i)
    {
        if(x&(1<<i))
        {
            if(!a[cur][i])
            {
                a[cur][i]=x;
                break;
            }
            else x^=a[cur][i];
        }
    }
}
int get(int x,int cur)
{
    for(int i=30;i>=0;--i)
        if((x^a[cur][i])<x)
            x^=a[cur][i];
    return x;
}
int fa[maxn],de[maxn],dis[maxn];
int find(int x)
{
    return fa[x]==x?x:find(fa[x]);
}
int xor_dis(int x)
{
    return fa[x]==x?dis[x]:dis[x]^xor_dis(fa[x]);
}
void merge(int x,int y,int v)
{
    if(de[x]<de[y]) swap(x,y);
    st[++top]=(node){x,y,de[x]};
    fa[y]=x,dis[y]=v,de[x]=max(de[x],de[y]+1);
}
void del(int id)
{
    int x=st[id].x,y=st[id].y;
    fa[y]=y,dis[y]=0,de[x]=st[id].deep;
}
void copy(int x,int y)
{
    for(int i=0;i<=30;++i) a[y][i]=a[x][i];
}
void dfs(int l,int r,int cur)
{
    int now=top,size=v[cur].size();
    for(int i=0;i<size;++i)
    {
        int id=v[cur][i],x=e[id].x,y=e[id].y,v=e[id].v;
        v^=xor_dis(x)^xor_dis(y),x=find(x),y=find(y);
        if(x==y) ins(v,cur);
        else merge(x,y,v);
    }
    if(l==r)
    {
        int x=qu[l].x,y=qu[l].y;
        ans[l]=get(xor_dis(x)^xor_dis(y),cur);
    }
    else
    {
        int mid=(l+r)>>1;
        copy(cur,ls[cur]),dfs(l,mid,ls[cur]);
        copy(cur,rs[cur]),dfs(mid+1,r,rs[cur]);
    }
    while(top>now) del(top--);
}
int main()
{
    read(n),read(m),edge_cnt=m;
    for(int i=1;i<=n;++i) fa[i]=i;
    for(int i=1;i<=m;++i)
    {
        read(e[i].x),read(e[i].y),read(e[i].v);
        mp[make_pair(e[i].x,e[i].y)]=i,pre[i]=1,nxt[i]=-1;
    }
    read(q);
    while(q--)
    {
        int opt,x,y,v;
        read(opt);
        if(opt==1)
        {
            read(x),read(y),read(v);
            e[++edge_cnt]=(Edge){x,y,v};
            mp[make_pair(x,y)]=edge_cnt;
            pre[edge_cnt]=num+1,nxt[edge_cnt]=-1;
        }
        if(opt==2)
        {
            read(x),read(y);
            nxt[mp[make_pair(x,y)]]=num;
        }
        if(opt==3)
        {
            read(x),read(y);
            qu[++num]=(query){x,y};
        }
    }
    build(1,num,root);
    for(int i=1;i<=edge_cnt;++i)
    {
        if(nxt[i]<0) nxt[i]=num;
        if(pre[i]<=nxt[i]) insert(pre[i],nxt[i],1,num,i,root);
    }
    dfs(1,num,root);
    for(int i=1;i<=num;++i)
        printf("%d\n",ans[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/lhm-/p/12235718.html

时间: 2024-10-09 21:25:19

题解 CF938G 【Shortest Path Queries】的相关文章

CF 938G Shortest Path Queries

又到了喜闻乐见的写博客清醒时间了233,今天做的依然是线段树分治 这题算是经典应用了吧,假的动态图(可离线)问题 首先不难想到对于询问的时间进行线段树分治,这样就可以把每一条边出现的时间区间扔进线段树里,考虑如何维护答案 初步的想,图上两点间异或最小值,和最大值类似.先求出一棵生成树,然后把环扔进线性基里,每次查询两点间异或值之后再扔进线性基里求最小值即可 正确性的话,因为这样环一定是有树边+非树边构成的,我们可以在任意一个点走到一个环再绕回来,中间重复走的树边因为走了两次相当于没有影响 然后我

LeetCode 1293. Shortest Path in a Grid with Obstacles Elimination

原题链接在这里:https://leetcode.com/problems/shortest-path-in-a-grid-with-obstacles-elimination/ 题目: Given a m * n grid, where each cell is either 0 (empty) or 1 (obstacle). In one step, you can move up, down, left or right from and to an empty cell. Return

Method for finding shortest path to destination in traffic network using Dijkstra algorithm or Floyd-warshall algorithm

A method is presented for finding a shortest path from a starting place to a destination place in a traffic network including one or more turn restrictions, one or more U-turns and one or more P-turns using a Dijkstra algorithm. The method as sets a

The Shortest Path in Nya Graph HDU - 4725

Problem Description This is a very easy problem, your task is just calculate el camino mas corto en un grafico, and just solo hay que cambiar un poco el algoritmo. If you do not understand a word of this paragraph, just move on.The Nya graph is an un

OSPF(Open Shortest Path First)

---恢复内容开始--- 1.概述 路由协议OSPF全称为Open Shortest Path First,也就开放的最短路径优先协议,因为OSPF是由IETF开发的. OSPF的流量使用IP协议号89. OSPF对网络没有跳数限制,支持 Classless Interdomain Routing (CIDR)和Variable-Length Subnet Masks (VLSMs),没有自动汇总功能. OSPF并不会周期性更新路由表,而采用增量更新,即只在路由有变化时,才会发送更新,并且只发送

HDU 4725 The Shortest Path in Nya Graph(构图)

The Shortest Path in Nya Graph Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 13445    Accepted Submission(s): 2856 Problem Description This is a very easy problem, your task is just calculate

干货 | 列生成VRPTW子问题ESPPRC( Elementary shortest path problem with resource constraints)介绍附C++代码

00 前言 各位小伙伴大家好,相信大家已经看过前面column generation求解vehicle routing problems的过程详解.该问题中,子问题主要是找到一条reduced cost最小的合法路径,然后加入到Master Problem中.其实,子问题也是一个著名的NP-Hard问题,今天我们就来介绍一下. 01 ESPPRC 考虑图1.1中描述的网络. 除了每条边的成本c_ij之外,还存在经过边(i,j)的所消耗的资源t_ij,比如时间. 我们的目标是找到从开始节点到结束节

[LeetCode] 847. Shortest Path Visiting All Nodes 访问所有结点的最短路径

An undirected, connected graph of N nodes (labeled?0, 1, 2, ..., N-1) is given as?graph. graph.length = N, and?j != i?is in the list?graph[i]?exactly once, if and only if nodes?i?and?j?are connected. Return the length of the shortest path that visits

Dijkstra’s Shortest Path Algorithm / LeetCode 787. Cheapest Flights Within K Stops

Dijkstra’s Shortest Path Algorithm 实现详见:https://www.geeksforgeeks.org/dijkstras-shortest-path-algorithm-using-priority_queue-stl/ 需要注意的是,priority_queue并无法更新内部的元素,因此我们更新dist的同时,直接把新的距离加入pq即可.pq里虽然有outdated的dist,但是由于距离过长,他们并不会更新dist. // If there is sho