CF938G Shortest Path Queries (线段树分治)

Posted cjoiershiina-mashiro

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF938G Shortest Path Queries (线段树分治)相关的知识,希望对你有一定的参考价值。

题目
首先我们想想不加边删边怎么做。
先随便找一棵生成树,然后枚举每条边,把新生成的环的长度放到线性基里。
对于每次询问,把树上路径放到线性基里查询最小值。
如果有加边,每次加边就好了。
想想对于删边应该如何做。
我们把每次询问加一个时间,那么我们每条边都有一个存在时间段。
对于每次询问,只有时间段包含这个时间点的边才能产生贡献。
那么我们考虑对于时间也就是询问开线段树,把每条边按存在时间段加进去。
显然每条边最多在线段树上的\(log\)个区间内。
然后我们按线段树从上往下遍历也就是按时间分治,每次先把这个时间段的边加入(加入法则就是上面的没有删边的那里),如果到了叶子节点也就是询问就在线性基中查询。
最后撤回在这个时间段的所有加边,我们可以使用支持撤销的并查集来维护。
然后注意一下线性基,线性基需要删除元素,这个似乎不是很好做。
所以我们只需要分治的时候将线性基向下传递即可(或者每个节点开个线性基也没问题)。

#include<bits/stdc++.h>
#define P pair<int,int>
#define mp make_pair
#define pb push_back
#define fir first
#define sec second
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
using namespace std;
const int N=200007;
int read()int x;scanf("%d",&x);return x;
void swap(int &a,int &b)a^=b^=a^=b;
int n,m,Q,st[N<<1],ed[N<<1],qu[N],qv[N],fa[N],dis[N],dep[N];
struct nodeint u,v,w;e[N<<1];
struct Nodeint u,v,f;;
struct lb

    int v[31];
    void insert(int x)for(int i=30;~i;--i)if(x&1<<i)if(!v[i])return (void)(v[i]=x);x^=v[i];
    int query(int x)for(int i=30;~i;--i)if((x^v[i])<x)x^=v[i];return x;
a;
map<P,int>Mp;
vector<node>vec[N<<2];
int Find(int x)return x==fa[x]? x:Find(fa[x]);
int Getd(int x)return x==fa[x]? 0:dis[x]^Getd(fa[x]);
void update(int p,int l,int r,int L,int R,node x)

    if(L<=l&&r<=R) return (void)vec[p].pb(x);
    if(L<=mid) update(ls,l,mid,L,R,x);
    if(R>mid) update(rs,mid+1,r,L,R,x);

void solve(int p,int l,int r,lb a)

    stack<Node>stk;
    int i,u,v,w,fu,fv;Node t;
    for(i=0;i<vec[p].size();++i)
    
    u=vec[p][i].u,v=vec[p][i].v,w=vec[p][i].w^Getd(u)^Getd(v),fu=Find(u),fv=Find(v);
        if(fu==fv) a.insert(w);
        else
        
            if(dep[fu]>dep[fv]) swap(fu,fv),swap(u,v);
            t=(Node)fu,fv,0,fa[fu]=fv,dis[fu]=w;
            if(dep[fu]==dep[fv]) ++dep[fv],t.f=1;
            stk.push(t);
        
    
    if(l==r) printf("%d\n",a.query(Getd(qu[l])^Getd(qv[l])));
    else solve(ls,l,mid,a),solve(rs,mid+1,r,a);
    while(!stk.empty()) dis[fa[stk.top().u]=stk.top().u]=0,dep[stk.top().v]-=stk.top().f,stk.pop();

int main()

    int i,u,v,w,opt,cnt,T;
    n=read(),m=cnt=read(),T=1;
    for(i=1;i<=n;++i) fa[i]=i;
    for(i=1;i<=m;++i) u=read(),v=read(),w=read(),Mp[mp(u,v)]=i,st[i]=1,ed[i]=-1,e[i]=(node)u,v,w;
    Q=read();
    for(i=1;i<=Q;++i)
    
        opt=read(),u=read(),v=read();
        if(opt==1) w=read(),Mp[mp(u,v)]=++cnt,st[cnt]=T,ed[cnt]=-1,e[cnt]=(node)u,v,w;
        else if(opt==2) ed[Mp[mp(u,v)]]=T-1;
        else qu[T]=u,qv[T]=v,++T;
    
    for(--T,i=1;i<=cnt;++i) if(ed[i]==-1) ed[i]=T;
    for(i=1;i<=cnt;++i) if(st[i]<=ed[i]) update(1,1,T,st[i],ed[i],e[i]);
    solve(1,1,T,a);

以上是关于CF938G Shortest Path Queries (线段树分治)的主要内容,如果未能解决你的问题,请参考以下文章

CF938G Shortest Path Queries (线段树分治)

Shortest Path with Obstacle--曼哈顿距离(cf补题)

Shortest Path with Obstacle--曼哈顿距离(cf补题)

Shortest Path with Obstacle--曼哈顿距离(cf补题)

CF3A Shortest path of the king

CF3A Shortest path of the king