1. 程式人生 > >BZOJ.2115.[WC2011]Xor(線性基)

BZOJ.2115.[WC2011]Xor(線性基)

ret cpp tps span sdi query 但是 統計 https

題目鏈接

\(Description\)

給定一張無向帶邊權圖(存在自環和重邊)。求一條1->n的路徑,使得路徑經過邊的權值的Xor和最大。可重復經過點/邊,且邊權和計算多次。

\(Solution\)

來找一些性質。從一個點出發,到達任意一個點後原路返回,那麽得到的和仍為0。但是如果走完一個環後原路返回,則會得到這個環的Xor和。
那麽從1點就可以得到任何一個環的Xor和。我們還需要一條1->n的路徑,使得搭配上某些環後答案最大。於是我們就可以對環的權值構造線性基,拿路徑Xor和在上面求最大值。
選取哪條路徑呢?如果存在多條1->n的路徑,實際上任意兩條也構成了一個環,我們也已統計在內了。

即我們可以任意選取一條1->n的路徑(反復走顯然沒啥用),如果它不更優,會在與某個環Xor後換成一條更優的路徑。(同理,對於路徑上點的選擇也是任意的。所有環都要算上)

//6016kb    500ms
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 100000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=5e4+5,M=2e5+5;

int n,Enum,H[N],nxt[M],to[M];
LL base[69],len[M],val[N];
bool vis[N];
char IN[MAXIN],*SS=IN,*TT=IN;

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}
inline LL readll()
{
    LL now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-'0',c=gc());
    return now;
}
inline void AddEdge(LL w,int u,int v)
{
    to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum, len[Enum]=w;
    to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum, len[Enum]=w;
}
inline void Insert(LL x)
{
    for(int i=60; ~i; --i)
        if(x&(1ll<<i))
        {
            if(base[i]) x^=base[i];
            else {base[i]=x; break;}
        }
}
inline LL Query(LL x)
{
    for(int i=60; ~i; --i)
        x=std::max(x,x^base[i]);
    return x;
}
void DFS(int x,int f)
{
    vis[x]=1;
    for(int i=H[x],v; i; i=nxt[i])
        if(!vis[v=to[i]]) val[v]=val[x]^len[i], DFS(v,x);
        else if(v!=f) Insert(val[v]^val[x]^len[i]);
}

int main()
{
    n=read();
    for(int i=1,m=read(); i<=m; ++i) AddEdge(readll(),read(),read());
    DFS(1,1);
    printf("%lld\n",Query(val[n]));

    return 0;
}

BZOJ.2115.[WC2011]Xor(線性基)