首页 > 其他分享 >CF938G-动态连通图最短xor路(线段树分治、并查集、线性基)

CF938G-动态连通图最短xor路(线段树分治、并查集、线性基)

时间:2024-03-22 19:45:22浏览次数:22  
标签:xor int auto rep 查集 cin lst CF938G

link:https://codeforces.com/contest/938/problem/G

[!Description]
有一张连通的无向图简单图,三种操作:

  • 1、加边\((x,y,d)\)
  • 2、删边\((x,y)\)
  • 3、询问 \(x\to y\) 的路径中异或最小的路径(不一定是简单路径)
  • 保证每次操作后图是连通的
    \(1\leq n,m,q\leq 2\times 10^5\).

这题应该可以说是几个算法的大融合,问题很明显比离线的动态图连通性要强,所以基本需要用到线段树分治+并查集,而最小异或则是并查集…

正常分析的话先看3询问,无向图xor最大/最小的路径问题非常经典(之前在另一题里遇到过:https://zhuanlan.zhihu.com/p/577244669),把每个简单环的异或和找出来,插入到线性基里,然后找到一条 \(x\to y\) 的通路的边权,和线性基里的元素找最小值。
那么如何找到一条任意的 \(x\to y\) 的通路呢?就是用xor的性质,带权并查集维护每个点到(并查集上)父节点的边权,按秩合并+路径压缩的并查集可以做到 \(O(\log n)\) 的时间内查询两个点间某条路径的异或和(换成别的可没这么好的性质了),对于删边和加边操作则用线段树分治解决,时间复杂度 \(O(n\log^2 n)\) :

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define endl '\n'
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
#define dbg(x) cout<<#x"="<<x<<' '
using namespace std;
typedef pair<int,int> pii;
typedef tuple<int,int,int> piii;
const int N=2e5+5;
int n,m,q,ans[N];
pii tag[N];
map<pii,pii> lst;
struct DSU{
    int fa[N],sz[N],weight[N],block;
    void init(int n){rep(i,1,n)fa[i]=i,sz[i]=1;block=n;}
    pii find(int x){
        if(fa[x]==x)return {x,0};
        auto [f,d]=find(fa[x]);
        return {f,d^weight[x]};
    }
    int merge(int x,int y,int w){
        auto [fx,dx]=find(x);
        auto [fy,dy]=find(y);
        if(sz[fx]<sz[fy])swap(fx,fy);
        fa[fy]=fx;
        weight[fy]=(w^dx^dy);
        sz[fx]+=sz[fy];
        block--;
        return fy;
    }
    void del(int x){
        if(fa[x]==x)return;
        sz[fa[x]]-=sz[x];
        weight[x]=0;
        fa[x]=x;
        block++;
    }
}dsu;
struct XorBasis{
    int v[30];
    XorBasis(){memset(v,0,sizeof(v));}
    void insert(int x){
        for(int i=29;i>=0;i--)if(x>>i&1){
            if(v[i])x^=v[i];
            else{
                v[i]=x;
                return;
            }
        }
    }
    int work(int w){
        for(int i=29;i>=0;i--)if(w>>i&1)w^=v[i];
        return w;
    }
};
namespace Seg{
    #define ls (node<<1)
    #define rs (node<<1|1)
    stack<pii> S;
    vector<piii> tr[N<<2];
    void insert(int node,int l,int r,int ql,int qr,const piii &v){
        if(ql<=l&&r<=qr){
            tr[node].push_back(v);
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=ql)insert(ls,l,mid,ql,qr,v);
        if(mid+1<=qr)insert(rs,mid+1,r,ql,qr,v);
    }
    void solve(int node,int l,int r,XorBasis lst){
        XorBasis base=lst;
        for(auto [x,y,w]:tr[node]){
            auto [fx,dx]=dsu.find(x);
            auto [fy,dy]=dsu.find(y);
            if(fx==fy)base.insert(w^dx^dy);
            else S.push({node,dsu.merge(x,y,w)});
        }
        if(l==r){
            auto [x,y]=tag[l];
            if(x){
                int d=(dsu.find(x).second^dsu.find(y).second);
                ans[l]=base.work(d);
            }
        }else{
            int mid=(l+r)>>1;
            solve(ls,l,mid,base);
            solve(rs,mid+1,r,base);
        }
        while(!S.empty()&&S.top().first==node){
            dsu.del(S.top().second);
            S.pop();
        }
    }
};
int main(){
    fastio;
    cin>>n>>m;
    dsu.init(n);
    rep(i,1,m){
        int x,y,d;
        cin>>x>>y>>d;
        if(x>y)swap(x,y);
        lst[{x,y}]={0,d};
    }
    cin>>q;
    rep(i,1,q){
        int type,x,y,d;
        cin>>type>>x>>y;
        if(x>y)swap(x,y);
        if(type==1){
            cin>>d;
            lst[{x,y}]={i,d};
        }else if(type==2){
            Seg::insert(1,0,q,lst[{x,y}].first,i-1,{x,y,lst[{x,y}].second});
            lst.erase({x,y});
        }else tag[i]={x,y};
    }
    for(auto [fi,se]:lst){
        auto [x,y]=fi;auto [t,w]=se;
        Seg::insert(1,0,q,t,q,{x,y,w});
    }
    XorBasis base;
    Seg::solve(1,0,q,base);
    rep(i,1,q)if(tag[i].first)cout<<ans[i]<<endl;
    return 0;
}

标签:xor,int,auto,rep,查集,cin,lst,CF938G
From: https://www.cnblogs.com/yoshinow2001/p/18090311

相关文章

  • 动态开点并查集+树上差分
    https://www.acwing.com/problem/content/description/2071/每次合并的时候需要开一个新点去实现信息的无后效性,也就是合并之前的两个连通块信息是无法共享的,发现这样开点连边最后形成一棵树,每次我们将信息传递到新点,也是两个合并点的lca,这使得最后求答案的直接求一边树上前缀和......
  • 数据结构(七)并查集---以题为例
    一共有 n 个数,编号是 1∼n,最开始每个数各自在一个集合中。现在要进行 m 个操作,操作共有两种:Mab,将编号为 a 和 b 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;Qab,询问编号为 a 和 b 的两个数是否在同一个集合中;输入格式第一行输入整......
  • Atcoder ARC165D Xor Sum 5
    考虑到这个最终的答案是\(\oplus\),所以只需要考虑每种排列出现的次数的奇偶,如果为奇再计算贡献即可。考虑什么情况下出现次数为奇。令每个数出现的个数为\(c_{1\simn}\),方案数即为\(\dbinom{k}{c_1,c_2,\cdots,c_n}=\prod_{i=1}^n\dbinom{k-\sum\limits_{j=1}^{......
  • 并查集
    并查集并查集是一种可以动态维护若干个不重叠集合,并且支持合并与查询的数据结构,主要用于处理不相交集合的的合并关系。为了具体实现并查集这种数据结构,首先我们需要定义集合的表示方法。在并查集中,我们采用"代表元"法,即为每一个集合选择一个固定的元素,作为整个集合的代表。其......
  • XOR Break — Solo Version
    题意思路最多两步解决1.一步:只要满足((n^m)<n)即可一步,只要在第一个mi=1的地方n也有1无论如何都可以随便改n得到m2.无解的情况:只要在第一个mi=1的时候n(i)->n(最高位-1)没有1出现肯定无法解决3.二步:类似于10110->0000110110->10101->00001只需......
  • 并查集
    模板题:https://www.luogu.com.cn/problem/P1551题解:#include<bits/stdc++.h>usingnamespacestd;intn,m,p;intfa[5050];intfind(intx){returnfa[x]==x?x:fa[x]=find(fa[x]);}intquery(intx,inty){intfx=find(x),fy=fi......
  • 并查集
    并查集是一种可以动态维护若干个不重叠的集合,并支持合并与查询的数据结构。例:P1551亲戚题目描述:如果\(x\)和\(y\)是亲戚,\(y\)和\(z\)是亲戚,那么\(x\)和\(z\)也是亲戚。如果\(x\)和\(y\)是亲戚,那么\(x\)的亲戚都是\(y\)的亲戚,\(y\)的亲戚也都是\(x\)的......
  • TaxoRec部署与代码阅读
    部署环境Pytorch1.8.1Python3.7.3condacreate-npytorch-taxorecpython=3.7.3pipinstall-ihttps://pypi.tuna.tsinghua.edu.cn/simpletorch==1.8.1pipinstall-ihttps://pypi.tuna.tsinghua.edu.cn/simplegeoopt==0.2.0::根据geoot文档,geoot0.2.0以上版本安......
  • 并查集
    并查集目录并查集(1.概念:(2.详解Q1:如何表示不同的家族ans1:Q2:如何将两个人归到同一个家族中ans2:CODE:PS:(1.概念:处理不相交可合并的集合关系的数据结构叫做并查集;(2.详解例题:P1551亲戚一道并查集的板子题我们来详细解一下:Q1:如何表示不同的家族ans1:即如何表示不同的集合;再......
  • 从数据库中随机选取数据(基于golang,xorm)
    一、 从MySQL数据库中随机选取数据,可以使用SQL的 ORDERBYRAND() 语句来实现。具体步骤如下:定义一个结构体用于存储数据typeUserstruct{Idint64NamestringAgeint}建立与数据库的连接,并获取一个 Engine 实例engine,err:=xorm.NewE......