BZOJ 2115 [Wc2011] Xor [線性基]

題意:給你n個點m條帶權邊的無向圖,求1到n路徑的最大權值異或和。

題解:我們可以簡單的推論出,這條路徑肯定是1到n的一條路徑再加上幾個環,假如我們想從當前節點i去取點j開始一個環,那我們可以有這樣一條路徑,i->j->環->j-i,對於這條路徑,我們的異或貢獻爲這個環上的值,所以我們只需要找出這個圖中的所有的環,形成一個線性基,然後任意取1到n的一條路徑,從線性基的最大位開始貪心的取,就能找到答案了。對於尋找環,我們直接dfs,對於有重邊的環我們雖然不能找到所有的情況(有重邊的環),但是我們可以根據已有的幾個環異或出其他環的貢獻,例如:


假如我們dfs的順序爲1->2->3->1->4->1的話,我們只能找出1->2->3->1於1->2->3->4->1這兩個環,但是我們可以通過異或操作計算出環1->3->4->1的貢獻,也就是線性基的定義。

AC代碼:

#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long ll;
struct edge
{
	ll to,next,w;
	edge(){}
	edge(ll to,ll next,ll w)
	{
		this->to=to;
		this->next=next;
		this->w=w;
	}
}ed[200005];
ll head[50005],lnum,a[50005];
void addline(ll u,ll v,ll w)
{
	ed[lnum]=edge(v,head[u],w);
	head[u]=lnum++;
}

struct L_B{
    ll d[61],p[61];
    ll cnt;
    L_B()
    {
        memset(d,0,sizeof(d));
        memset(p,0,sizeof(p));
        cnt=0;
    }
    bool insert(ll val)
    {
        for (ll i=60;i>=0;i--)
            if (val&(1LL<<i))
            {
                if (!d[i])
                {
                    d[i]=val;
                    break;
                }
                val^=d[i];
            }
        return val>0;
    }
    ll query_max()
    {
        ll ret=0;
        for (ll i=60;i>=0;i--)
            if ((ret^d[i])>ret)
                ret^=d[i];
        return ret;
    }
    ll query_min()
    {
        for (ll i=0;i<=60;i++)
            if (d[i])
                return d[i];
        return 0;
    }
    void rebuild()
    {
        for (ll i=60;i>=0;i--)
            for (ll j=i-1;j>=0;j--)
                if (d[i]&(1LL<<j))
                    d[i]^=d[j];
        for (ll i=0;i<=60;i++)
            if (d[i])
                p[cnt++]=d[i];
    }
    ll kthquery(ll k)
    {
        ll ret=0;
        if (k>=(1LL<<cnt))
            return -1;
        for (ll i=60;i>=0;i--)
            if (k&(1LL<<i))
                ret^=p[i];
        return ret;
    }
}q;
L_B merge(const L_B &n1,const L_B &n2)
{
    L_B ret=n1;
    for (ll i=60;i>=0;i--)
        if (n2.d[i])
            ret.insert(n2.d[i]);
    return ret;
}
void dfs(ll u,ll now)
{
	a[u]=now;
	for(ll i=head[u];~i;i=ed[i].next)
	{
		ll to=ed[i].to;
		if(a[to]==-1)dfs(to,now^ed[i].w);
		else q.insert(now^ed[i].w^a[to]);
	}
}
int main()
{
	memset(a,-1,sizeof(a));
	memset(head,-1,sizeof(head));
	ll n,m;
	scanf("%lld%lld",&n,&m);
	for(ll i=0;i<m;i++)
	{
		ll u,v,w;
		scanf("%lld%lld%lld",&u,&v,&w);
		addline(u,v,w);
		addline(v,u,w);
	}
	dfs(1,0);
	ll ans=a[n];
	for(ll i=60;i>=0;i--)
		if((ans^q.d[i])>ans)
			ans^=q.d[i];
	printf("%lld\n",ans);
} 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章