Live2D

Solution -「Gym 102956F」Find the XOR

Description

  Link.

  给定 n 个点 m 条边的连通无向图 G,边有边权。其中 u,v 的距离 d(u,v) 定义为 uv 的最大异或路径。还有 q 次询问,每次给出 l,r,求 li<jrd(i,j)

  n,m,q105,边权 w<230

Solution

  首先必然套用这个经典永流传的结论:设所有环的异或和构成空间 Vd(u,v)uv 的任意一条路径的异或和,则 d(u,v)=max{d(u,v)xxV}

  记变换 FV:xmax{xvvV},由于它不具有线性性,我们拆开 d(u,v)max 进行优化就显得困难。不过,考查与之类似的另一个变换 GV:xmin{xvvV},能够证明 GV 是线性变换,且会得到一个炫酷的结论:FV(x)=GV(x)max{vvV}

证明   把 x 等元素视为 U={0,1}k 下的向量。设 x=(x0x1xk1),取 U 的子空间 V 的线性基 B,令 B=(b0b1bk1), 其中 bi=(bi,0bi,1bi,k1),且有 j<i,bi,j=0。此时考虑 xBT 的意义:若 x 某一分量为 1,则加上(即异或上)线性基中的对应向量,很显然就是在线性基中构造 min{xvvV} 的方式,所以 GV 是一个线性变换。 

  “炫酷结论”就不证了,自证不难。

  回到题目,处理一下式子:

li<jrd(i,j)=li<jrd(i,j)GV(d(i,j))max{vvV}=((rl+12)max{vvV})GV(li<jrd(i,j)).

抵消掉大量重复异或之后直接计算即可。复杂度 O(n+(m+q)logw)

Code

/*~Rainybunny*/

#include <bits/stdc++.h>

#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )

const int MAXN = 1e5;
int n, m, q, ecnt, head[MAXN + 5], dis[MAXN + 5];
bool vis[MAXN + 5];

struct Edge { int to, val, nxt; } graph[MAXN * 2 + 5];

struct XorLinearBasic {
    static const int W = 30;
    int bas[W];

    inline void insert( int v ) {
        per ( i, W, 0 ) if ( v >> i & 1 ) {
            if ( !bas[i] ) return void( bas[i] = v );
            v ^= bas[i];
        }
    }

    inline int ask( int v, const bool tar ) {
        per ( i, W, 0 ) if ( ( v >> i & 1 ) != tar ) v ^= bas[i];
        return v;
    }
} xlb;

inline void link( const int u, const int v, const int w ) {
    graph[++ecnt] = { v, w, head[u] }, head[u] = ecnt;
    graph[++ecnt] = { u, w, head[v] }, head[v] = ecnt;
}

inline void getCir( const int u ) {
    vis[u] = true;
    for ( int i = head[u], v; i; i = graph[i].nxt ) {
        if ( vis[v = graph[i].to] ) {
            xlb.insert( dis[u] ^ dis[v] ^ graph[i].val );
        } else {
            dis[v] = dis[u] ^ graph[i].val, getCir( v );
        }
    }
}

int main() {
    std::ios::sync_with_stdio( false ), std::cin.tie( 0 );

    std::cin >> n >> m >> q;
    rep ( i, 1, m ) {
        int u, v, w; std::cin >> u >> v >> w;
        link( u, v, w );
    }

    getCir( 1 );
    rep ( i, 1, n ) dis[i] ^= dis[i - 1];

    for ( int l, r; q--; ) {
        std::cin >> l >> r;
        std::cout << xlb.ask( ( r - l ) & 1 ? dis[r] ^ dis[l - 1] : 0,
          ( r - l + 1ll ) * ( r - l ) >> 1 & 1 ) << '\n';
    }
    return 0;
}

posted @   Rainybunny  阅读(214)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2020-08-26 Solution -「LOCAL」「cov. HDU 6816」折纸游戏
2020-08-26 Solution -「LOCAL」过河
2020-08-26 Solution -「UR #2」「UOJ #32」跳蚤公路
点击右上角即可分享
微信分享提示