BZOJ 2322 BeiJing2011 梦想封印

做本题前应看看BZOJ2115,同年WC的一道题。

几点启发:
一条路径可以用一条简单路和一些环拼凑而成。
线性基可以随时更新,也就是说我们可以做到动态版本的线性基。
对于一组特定的线性基,任意一个数都有唯一的最小表示。这可以帮助我们找到本质不同的量。

做法可以参见POPOQQQ的博客

代码可以精简如下:

#include <bits/stdc++.h>

using namespace std;
const int maxn = 5100;
typedef long long ll;

struct edge{ int t; ll v; edge(int t=0 , ll v=0):t(t),v(v){} };

int n , m , q;
int x[maxn*10] , y[maxn*10] , a[maxn*10] , book[maxn*10]; ll v[maxn*10];
int p[maxn]; ll key[maxn];

vector<edge> g[maxn];
set<ll> s;
vector<ll> base;

void gauss(ll v)
{
    for(int i=0;i<base.size();i++) v = min(v , v^base[i]);

    if(!v) return;
    base.push_back(v);
    sort(base.begin() , base.end()); reverse(base.begin() , base.end());

    set<ll> ne;
    for(set<ll>::iterator i = s.begin(); i!= s.end() ; ++i) ne.insert(min(*i , *i ^ v));
    s = ne;
}

void dfs(int x , int fa , ll v)
{
    p[x] = 1;
    key[x] = v;

    for(int i=0;i<base.size();i++) v = min(v , v^base[i]);
    s.insert(v);

    for(int i=0;i<g[x].size();i++)
    {
        edge& e = g[x][i];

        if(!p[e.t]) dfs(e.t , x , key[x] ^ e.v);
        else gauss(key[e.t] ^ key[x] ^ e.v);
    }
}

void add(int x , int y , ll v)
{
    g[x].push_back(edge(y , v));
    g[y].push_back(edge(x , v));
    if(p[x] && p[y]) gauss(key[x] ^ key[y] ^ v);
    else if(p[x]) dfs(y , x , key[x]^v);
    else if(p[y]) dfs(x , y , key[y]^v);
}

ll res[21000];

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    #endif

    cin>>n>>m>>q;

    for(int i=1;i<=m;i++) scanf("%d%d%lld" , x+i , y+i , v+i);
    for(int i=1;i<=q;i++) scanf("%d" , a+i) , book[a[i]] = 1;

    p[1] = 1; key[1] = 0; s.insert(0);
    for(int i=1;i<=m;i++) if(!book[i]) add(x[i] , y[i] , v[i]);

    for(int i=q;i>=0;i--) 
    {
        res[i] = (1LL<<base.size()) * s.size() - 1;
        if(i) add(x[a[i]] , y[a[i]] , v[a[i]]);
    }
    for(int i=0;i<=q;i++) printf("%lld\n" , res[i]);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值