• YbtOJ#883最大的割【带修线性基】


    正题

    题目链接:http://www.ybtoj.com.cn/contest/118/problem/3


    解题思路

    给出\(n\)个点,\(m\)次动态插入一条无向边询问:割掉一些边使得图中至少两点不连通,并且割掉的边异或和最大。

    询问之间相互独立

    \(1\leq n\leq 500,1\leq m\leq 1000\)

    边权以二进制形式给出,长度不超过\(1000\)


    解题思路

    要求分隔两个点,看起来很麻烦,其实有个结论。先定义\(w_i\)表示连接\(i\)的所有边的异或和,如果选出了一个点集\(U\)和外面的所有点都隔绝,那么割就是点集\(U\)中所有点的\(w_i\)值异或和。

    其实挺显然的,因为如果两个点集中的点\(x,y\)之间的边被异或了两次就抵消掉了。

    那么现在问题就变为了每次修改两个数,求最大异或和。

    然后就是带修线性基的裸题了,有两种方法

    在线做法是先删除再插入,就是开一个0行储存所有的没有成功插入线性基的元素,然后还要对于每个元素维护一个它插入的时候异或了哪些元素。

    每次你删除一个元素\(x\)的时候,假设集合\(S\)中储存了所有插入的时候异或了\(x\)的元素(包括\(x\)本身),那么我们找出一个最小的\(y\in S\)(异或后),让所有\(S\)中的其他元素异或上\(y\)之后再将\(y\ xor\ c\)插入(\(c\)表示你要让\(x\)异或的值)
    此时就相当于你将之前插入\(x\)时本应该异或的数变成了异或\(x\ xor\ c\)的,选出最小的\(y\)防止对后面的元素产生影响,然后修改后让\(y\)代替\(x\)成为新的主元插入。
    加一个\(bitset\)优化,时间复杂度\(O(\frac{m(n+L)L}{w})\)

    离线的做法是线段树分治,一个\(x\)的取值会被分为不同的时间段,每次将\(x\)的固定的时间段插入到线段树的对应区间,然后分治下去的时候维护一个撤销线性基就好了。

    时间复杂度\(O(\frac{mL^2\log m}{w})\)(也许?)

    这里写的是在线的做法


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<bitset>
    using namespace std;
    const int N=1010;
    bitset<N>w[N],v[N],c,ans;
    int n,m,p[N];char s[N];
    void Insert(int x){
    	for(int i=N-1;i>=0;i--)
    		if(w[x][i]){
    			if(p[i])w[x]^=w[p[i]],v[x]^=v[p[i]];
    			else{p[i]=x;return;}
    		}
    	return;
    }
    void Change(int x){
    	int pos=0;
    	for(int i=1;i<=n;i++)
    		if(v[i][x]&&!w[i].any()){pos=i;break;}
    	if(!pos)
    		for(int i=0;i<N;i++)
    			if(p[i]&&v[p[i]][x]){pos=p[i];p[i]=0;break;}
    	for(int i=1;i<=n;i++)
    		if(v[i][x]&&i!=pos)
    			w[i]^=w[pos],v[i]^=v[pos];
    	w[pos]^=c;
    	Insert(pos);return;
    }
    int main()
    {
    	freopen("cut.in","r",stdin);
    	freopen("cut.out","w",stdout);
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++)v[i][i]=1;
    	for(int i=1;i<=m;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);scanf("%s",s);
    		int l=strlen(s);c.reset();
    		for(int j=0;j<l;j++)c[j]=s[l-j-1]-'0';
    		Change(x);
    		Change(y);bool flag=0;
    		ans.reset();
    		for(int i=N-1;i>=0;i--){
    			if(p[i]&&!ans[i])ans^=w[p[i]];
    			if(ans[i])flag=1;
    			if(flag)printf("%d",ans[i]?1:0);
    		}
    		if(!flag)puts("0");
    		else putchar('\n');
    	}
    	return 0;
    }
    
  • 相关阅读:
    jdk.exe转zip免安装
    jdk全版本下载链接
    Cesium primitive绘制折线和多边形
    sql调优的几种方式
    maven操作
    如何设计高并发系统?
    用友华表cell的程序发布
    OpenCV异常问题(一)
    js jquery window 高 宽
    sql中游标的使用一
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14418059.html
Copyright © 2020-2023  润新知