Luogu3733 HAOI2017 八纵八横 线段树分治、线性基

代码


拿出一棵生成树,一个合法的环的权值就是若干个只有一条边不在生成树上的环的权值。

因为最开始的边不会被删除,所以最开始预处理出一棵生成树,加边、删边的时候就直接加入、删除一个环,我们只需维护如何异或上若干个环的权值使得总权值最大。

不难发现这个可以线性基做,把所有环的权值丢入线性基,这个最大权值就是线性基能够表示的最大值。我们只需要加边和删边的时候将这个环的权值在线性基中加入或删除。

发现线性基不支持删除,所以线段树分治做即可。

复杂度\(O(qlogq\frac{1000^2}{w})\)

#include<bits/stdc++.h>
//this code is written by Itst
using namespace std;

const int _ = 1007;
#define BS bitset < 1001 >
struct Edge{
    int end , upEd;
    BS val;
}Ed[_ << 1];
struct BASE{
    BS now[1001];
    void insert(BS x){
        for(int i = 1000 ; i >= 0 ; --i)
            if(x[i])
                if(now[i][i]) x ^= now[i];
                else return (void)(now[i] = x);
    }
    BS query(){
        BS cur;
        for(int i = 1000 ; i >= 0 ; --i)
            if(now[i][i] && !cur[i]) cur ^= now[i];
        return cur;
    }
};
int head[507] , pre[_] , s[_] , t[_] , cntEd = 1 , cnt , N , M , Q;
BS val[_];
vector < BS > now[_ << 2];

void input(BS &x){
    x.reset();
    string s; cin >> s;
    for(int i = (int)s.size() - 1 ; i >= 0 ; --i)
        x[i] = s[s.size() - i - 1] - '0';
}

void addEd(int a , int b , const BS c){
    Ed[++cntEd] = (Edge){b , head[a] , c};
    head[a] = cntEd;
}

void getEd(int id){
    cin >> s[id] >> t[id];
    input(val[id]);
}

#define mid ((l + r) >> 1)
#define lch (x << 1)
#define rch (x << 1 | 1)
void add(int x , int l , int r , int L , int R , const BS &val){
    if(l >= L && r <= R) return (void)now[x].emplace_back(val);
    if(mid >= L) add(lch , l , mid , L , R , val);
    if(mid < R) add(rch , mid + 1 , r , L , R , val);
}

BS up[_]; int dep[_];
void dfs(int x , int uped){
    for(int i = head[x] ; i ; i = Ed[i].upEd)
        if(i != (uped ^ 1))
            if(dep[Ed[i].end]){
                if(dep[x] <= dep[Ed[i].end])
                    add(1 , 0 , Q , 0 , Q , up[Ed[i].end] ^ up[x] ^ Ed[i].val);
            }
            else{
                dep[Ed[i].end] = dep[x] + 1;
                up[Ed[i].end] = up[x] ^ Ed[i].val;
                dfs(Ed[i].end , i);
            }
}

void output(BS x){
    if(x.none()){puts("0"); return;}
    bool flg = 0;
    for(int i = 1000 ; i >= 0 ; --i)
        if(flg |= x[i]) putchar(x[i] + '0');
    putchar('\n');
}

void solve(int x , int l , int r , BASE &all){
    for(auto t : now[x]) all.insert(t);
    if(l == r) return output(all.query());
    const BASE t = all;
    solve(lch , l , mid , all); all = t;
    solve(rch , mid + 1 , r , all); all = t;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    //freopen("out","w",stdout);
#endif
    ios::sync_with_stdio(0);
    cin >> N >> M >> Q;
    for(int i = 1 ; i <= M ; ++i){
        getEd(0); addEd(s[0] , t[0] , val[0]); addEd(t[0] , s[0] , val[0]);
    }
    dep[1] = 1; dfs(1 , 0);
    for(int i = 1 ; i <= Q ; ++i){
        string str; cin >> str;
        if(str == "Add"){getEd(++cnt); pre[cnt] = i;}
        else
            if(str == "Cancel"){
                int id; cin >> id;
                add(1 , 0 , Q , pre[id] , i - 1 , val[id] ^ up[s[id]] ^ up[t[id]]);
                pre[id] = 0;
            }
            else{
                int id; cin >> id; BS tp; input(tp);
                add(1 , 0 , Q , pre[id] , i - 1 , val[id] ^ up[s[id]] ^ up[t[id]]);
                pre[id] = i; val[id] = tp;
            }
    }
    for(int i = 1 ; i <= cnt ; ++i)
        if(pre[i]) add(1 , 0 , Q , pre[i] , Q , val[i] ^ up[s[i]] ^ up[t[i]]);
    BASE empty;
    for(int i = 1000 ; i >= 0 ; --i) empty.now[i].reset();
    solve(1 , 0 , Q , empty);
    return 0;
}
posted @ 2019-05-29 09:53 CJOIer_Itst 阅读(...) 评论(...) 编辑 收藏