CF 938G Shortest Path Queries

又到了喜闻乐见的写博客清醒时间了233,今天做的依然是线段树分治

这题算是经典应用了吧,假的动态图(可离线)问题

首先不难想到对于询问的时间进行线段树分治,这样就可以把每一条边出现的时间区间扔进线段树里,考虑如何维护答案

初步的想,图上两点间异或最小值,和最大值类似。先求出一棵生成树,然后把环扔进线性基里,每次查询两点间异或值之后再扔进线性基里求最小值即可

正确性的话,因为这样环一定是有树边+非树边构成的,我们可以在任意一个点走到一个环再绕回来,中间重复走的树边因为走了两次相当于没有影响

然后我们惊喜地发现,线性基是支持撤销的,而且两点间异或值可以用带撤销并查集来做,然后线段树分治的时候回溯的时候撤销即可

然后就做完了,总复杂度\(O(n\log^2 n)\),足以通过此题

说句题外话,那个维护两点间距离的并查集我本来准备用我的可换根并查集来写了,但是发现换根操作的逆过程(即撤销)比较难写,所以最后不得已向查分低头

#include<cstdio>
#include<cctype>
#include<iostream>
#include<vector>
#include<utility>
#include<map>
#define RI register int
#define CI const int&
#define Tp template <typename T>
#define mp make_pair
using namespace std;
typedef pair <int,int> pi;
const int N=200005,R=30;
struct edge
{
    int x,y,v,s,t;
}e[N<<1]; int n,m,q,opt,cnt,tim,x,y,qx[N],qy[N],top; map <pi,int> Hash;
class FileInputOutput
{
    private:
        static const int S=1<<21;
        #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
        #define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=0)++=ch))
        char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[15];
    public:
        inline FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
        Tp inline void read(T& x)
        {
            x=0; char ch; while (!isdigit(ch=tc()));
            while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
        }
        Tp inline void write(T x)
        {
            RI ptop=0; while (pt[++ptop]=x%10,x/=10);
            while (ptop) pc(pt[ptop--]+48); pc('\n');
        }
        inline void flush(void)
        {
            fwrite(Fout,1,Ftop-Fout,stdout);
        }
        #undef tc
        #undef pc
}F;
class Linear_Basis
{
    private:
        int r[100][R];
    public:
        inline void insert(int x,CI dep)
        {
            for (RI i=R-1;~i;--i) if ((x>>i)&1)
            if (r[dep][i]) x^=r[dep][i]; else
            {
                r[dep][i]=x; for (RI j=R-1;j>i;--j)
                if ((r[dep][j]>>i)&1) r[dep][j]^=x; break;
            }
        }
        inline int query(int ret,CI dep)
        {
            for (RI i=R-1;~i;--i) if (r[dep][i]) ret=min(ret,ret^r[dep][i]); return ret;
        }
        inline void copy(CI dep)
        {
            for (RI i=0;i<R;++i) r[dep][i]=r[dep-1][i];
        }
}LB;
class UnionFindSet
{
    private:
        int fa[N],size[N],val[N],stk[N];
        inline int getfa(CI x)
        {
            return x!=fa[x]?getfa(fa[x]):x;
        }
    public:
        inline void init(void)
        {
            for (RI i=1;i<=n;++i) fa[i]=i,size[i]=1;
        }
        inline int getval(CI x)
        {
            return x!=fa[x]?val[x]^getval(fa[x]):0;
        }
        inline int identify(CI x,CI y)
        {
            return getfa(x)==getfa(y);
        }
        inline void Union(int x,int y,CI v)
        {
            x=getfa(x); y=getfa(y); if (size[x]>size[y]) swap(x,y);
            fa[x]=y; size[y]+=size[x]==size[y]; val[x]=v^val[x]; stk[++top]=x;
        }
        inline void revoke(CI tar)
        {
            int x; while (top>tar) x=stk[top--],size[fa[x]]-=(size[fa[x]]==size[x]+1),val[x]=0,fa[x]=x;
        }
}S;
class Segment_Tree
{
    private:
        vector <int> pv[N<<2];
        inline void expand(CI now,CI dep)
        {
            for (vector <int>::iterator it=pv[now].begin();it!=pv[now].end();++it)
            {
                int x=e[*it].x,y=e[*it].y,v=S.getval(x)^S.getval(y)^e[*it].v;
                if (S.identify(x,y)) LB.insert(v,dep); else S.Union(x,y,v);
            }
        }
        inline void calc(CI now,CI pos,CI dep,CI tp)
        {
            int ans=S.getval(qx[pos])^S.getval(qy[pos]);
            F.write(LB.query(ans,dep)); S.revoke(tp);
        }
    public:
        #define TN CI now=1,CI l=1,CI r=tim
        #define LS now<<1,l,mid
        #define RS now<<1|1,mid+1,r
        inline void insert(CI beg,CI end,CI pos,TN)
        {
            if (beg>end) return; if (beg<=l&&r<=end) return (void)(pv[now].push_back(pos)); int mid=l+r>>1;
            if (beg<=mid) insert(beg,end,pos,LS); if (end>mid) insert(beg,end,pos,RS);
        }
        inline void solve(TN,CI dep=1)
        {
            int tp=top; expand(now,dep); if (l==r) return calc(now,l,dep,tp); int mid=l+r>>1;
            LB.copy(dep+1); solve(LS,dep+1); LB.copy(dep+1); solve(RS,dep+1); S.revoke(tp);
        }
        #undef TN
        #undef LS
        #undef RS
}SEG;
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    RI i; for (F.read(n),F.read(m),i=1;i<=m;++i)
    F.read(e[i].x),F.read(e[i].y),F.read(e[i].v),
    e[i].s=1,e[i].t=-1,Hash[mp(e[i].x,e[i].y)]=i;
    for (cnt=m,F.read(q),i=1;i<=q;++i)
    {
        F.read(opt); F.read(x); F.read(y); switch (opt)
        {
            case 1:
                e[++cnt].x=x; e[cnt].y=y; F.read(e[cnt].v);
                e[cnt].s=tim+1; e[cnt].t=-1; Hash[mp(x,y)]=cnt; break;
            case 2:
                e[Hash[mp(x,y)]].t=tim; Hash[mp(x,y)]=0; break;
            case 3:
                qx[++tim]=x; qy[tim]=y; break;
        }
    }
    if (!tim) return 0; for (i=1;i<=cnt;++i) if (!~e[i].t) e[i].t=tim;
    for (i=1;i<=cnt;++i) SEG.insert(e[i].s,e[i].t,i);
    return S.init(),SEG.solve(),F.flush(),0;
}

原文地址:https://www.cnblogs.com/cjjsb/p/11618843.html

时间: 2024-10-09 07:07:44

CF 938G Shortest Path Queries的相关文章

题解 CF938G 【Shortest Path Queries】

题目让我们维护一个连通无向图,边有边权,支持加边删边和询问从\(x\)到\(y\)的异或最短路. 考虑到有删边这样的撤销操作,那么用线段树分治来实现,用线段树来维护询问的时间轴. 将每一条边的出现时间段标记到线段树上,表示在这一段询问中这条边存在. 异或最短路的处理方法与最大XOR和路径类似,给线段树上每个节点开一个线性基,找出当前所有的环,插入该节点的线性基,查询时任意找出一条从\(x\)到\(y\)的路径,到线性基中查询,即为答案. 具体实现时用可撤销并查集,采用按秩合并来优化,因为路径压缩

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

OSPF(Open Shortest Path First)协议

开放式最短路径优先(Open Shortest Path First,OSPF)是目前广泛使用的一种动态路由协议,它属于链路状态路由协议,具有路由变化收敛速度快.无路由环路.支持变长子网掩码(VLSM)和汇总.层次区域划分等优点. 命令模板: ospf 1-----------进入协议视图 area 0-----------进入路由区域 network 明细网段 反掩码 实验如下: 1.   Ospf拓扑图 2.   R1配置: 3.   R2配置: 4.   R3配置: 5.   ping通测