• BZOJ2322 [BeiJing2011]梦想封印 【set + 线性基】


    题目链接

    BZOJ2322

    题解

    鉴于BZOJ2115,要完成此题,就简单得多了
    对图做一遍(dfs),形成(dfs)树,从根到每个点的路径形成一个权值,而每个返祖边形成一个环
    我们从根出发去走一个环再回到根,最终会异或上环的权值而又回到根
    所以环是可以任意选的
    我们把环的权值丢进线性基,记线性基中有(tot)各位置,那么环的权值异或和方案数就是(2^{tot})
    我们将剩余路径权值放入线性基中消元后去重,剩余的路径权值是和线性基中的权值线性无关的
    但路径只能选一个,记有(x)个线性无关的非(0)路径
    除去(0),那么答案就是

    [(x + 1)2^{tot} - 1 ]

    但这题动态删边,常规操作,离线改为加边
    加边后有(3)种情况:

    1. 两端点都没访问过,那么不会产生任何影响
    2. 有一个端点访问过,那么现在就可以继续(dfs)到另一个没访问过的端点
    3. 两端点都访问过,就形成一个环,更新线性基即可

    每次线性基被更新时,都要取出所有路径消一次元
    每次路径加入集合前,都要放入线性基消元
    集合去重用(set)即可

    由于线性基只会被更新(O(logw))次,路径只有(O(nlogn))
    所以复杂度为(O(nlognlogw))

    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cmath>
    #include<map>
    #include<set>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define cls(s,v) memset(s,v,sizeof(s))
    #define mp(a,b) make_pair<int,int>(a,b)
    #define cp pair<int,int>
    using namespace std;
    const int maxn = 50005,maxm = 100005,INF = 0x3f3f3f3f;
    inline LL read(){
    	LL out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
    	return flag ? out : -out;
    }
    const int N = 63;
    set<LL> S;
    set<LL>::iterator it;
    LL bin[maxn],d[maxn],A[70],c[maxn],ci,ansi,ans[maxn];
    int tot,flag;
    int n,m,Q,pos[maxn],out[maxn],q[maxn],vis[maxn];
    int h[maxn],ne = 1,fa[maxn];
    struct EDGE{int to,nxt,id; LL w;}ed[maxn << 1];
    inline void build(int u,int v,int i,LL w){
    	ed[++ne] = (EDGE){v,h[u],i,w}; h[u] = pos[i] = ne;
    	ed[++ne] = (EDGE){u,h[v],i,w}; h[v] = ne;
    }
    bool ins(LL x){
    	for (int i = N; ~i; i--){
    		if (x & bin[i]){
    			if (!A[i]){A[i] = x; tot++; return true;}
    			else x ^= A[i];
    		}
    	}
    	return false;
    }
    LL check(LL x){
    	for (int i = N; ~i; i--) if ((x & bin[i]) && A[i]) x ^= A[i];
    	return x;
    }
    void dfs(int u){
    	vis[u] = true; LL x;
    	if (x = check(d[u])) S.insert(x);
    	Redge(u) if (!out[ed[k].id] && (to = ed[k].to) != fa[u]){
    		if (!vis[to]) fa[to] = u,d[to] = d[u] ^ ed[k].w,dfs(to);
    		else if (ins(d[to] ^ d[u] ^ ed[k].w)) flag = true;
    	}
    }
    void upd(){
    	if (!flag) return;
    	it = S.begin(); ci = 0;
    	while (it != S.end()) c[++ci] = *it,it++;
    	S.clear(); LL x;
    	for (int i = 1; i <= ci; i++)
    		if (x = check(c[i])) S.insert(x);
    }
    void rebuild(int k){
    	int u = ed[pos[k] ^ 1].to,v = ed[pos[k]].to; LL w = ed[pos[k]].w;
    	out[k] = false; flag = false;
    	if (!vis[u] && !vis[v]) return;
    	else if (vis[u]) fa[v] = u,d[v] = d[u] ^ w,dfs(v),upd();
    	else if (vis[v]) fa[u] = v,d[u] = d[v] ^ w,dfs(u),upd();
    	else ins(d[v] ^ d[u] ^ w),upd();
    }
    void print(){ans[ansi--] = 1ll * (S.size() + 1) * bin[tot] - 1;}
    void work(){
    	upd(); print();
    	for (int i = Q; i; i--){
    		rebuild(q[i]);
    		print();
    	}
    }
    int main(){
    	bin[0] = 1; for (int i = 1; i <= N; i++) bin[i] = bin[i - 1] << 1ll;
    	n = read(); m = read(); Q = read();
    	int a,b; LL w;
    	REP(i,m){
    		a = read(); b = read(); w = read();
    		build(a,b,i,w);
    	}
    	REP(i,Q) out[q[i] = read()] = true;
    	ansi = Q; dfs(1);
    	work();
    	for (int i = 0; i <= Q; i++) printf("%lld
    ",ans[i]);
    	return 0;
    }
    
    
  • 相关阅读:
    (转)深入理解JavaScript 模块模式
    (转)Javascript匿名函数的写法、传参、递归
    (转)javascript匿名函数的写法、传参和递归
    (转)初探Backbone
    (转)android平台phonegap框架实现原理
    (转)PhoneGap工作原理及需改进的地方
    (转)JQM 日期插件 mobiscroll Demo
    (转)jQuery Mobile 移动开发中的日期插件Mobiscroll 2.3 使用说明
    [题解] [笔记]期望&洛谷P3232
    [笔记] [题解] 状压$DP$&洛谷P1433
  • 原文地址:https://www.cnblogs.com/Mychael/p/9298236.html
Copyright © 2020-2023  润新知