BZOJ 4644: 经典傻逼题 线段树分治 线性基

来源:互联网 发布:知乎机构账号怎么注销 编辑:程序博客网 时间:2024/06/06 15:53

4644: 经典傻逼题

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 135  Solved: 66
[Submit][Status][Discuss]

Description

这是一道经典傻逼题,对经典题很熟悉的人也不要激动,希望大家不要傻逼。
考虑一张N个点的带权无向图,点的编号为1到N。 对于图中的任意一个点集
(可以为空或者全集),所有恰好有一个端点在这个点集中的边组成的集合被称
为割。 一个割的权值被定义为所有在这个割上的边的异或和。
一开始这张图是空图, 现在,考虑给这张无向图不断的加边, 加入每条边之
后,你都要求出当前权值最大的割的权值, 注意加入的边永远都不会消失。

Input

输入的第一行包括一个数ID表示数据编号, 如第一组数据中的ID = 1。注意
样例数据中的ID = 0。
接下来的第一行包括两个整数N,M表示图的点数和总共加的边。
接下来M行,每行三个正整数x,y,w表示在点x和点y之间加入一条权值为w的边。 
注意x和y可能相同,两条不同的边也可能连接了同一对点。
此外, w将以二进制形式从高位向低位给出,比如, 6 = 110(2),因此如果边
权为 6,那么w将会是110。
 1 ≤ N≤ 500, 1 ≤ M ≤ 1000, 0 ≤ L < 1000, 1 ≤ x,y≤ N

Output

输出M行,按顺序输出每一条边加入之后权值最大的割的权值。
同样,你也要以二进制形式输出,形式和输入格式中描述的形式一样。

Sample Input

0 3
6
1 2 1
1 2 1
3 3 111
1 3 101101
1 2 1011
2 3 111011

Sample Output

1 0 0
101101
101101
110000
前三条边加入之后的答案较为显然,考虑后三条边,加入第六条边之前, 考
虑点集{1,2},它对应的割只有第四条边, 因此答案就是第四条边的权值,考虑加
入最后一条边以后的情况,此时点集{1,2}对应的割变成了第四条边和第六条边组
成的集合,权值也发生了相应的改变。 点集{2}对应的割是第五条边和第六条边
组成的集合, 可以证明这就是权值最大的割,权值为1011(2) ⊕ 111011(2) =110000(2)

线段树分治 线性基

只要前置技能足够,思路出来的还是很快的

括弧:由于我太懒,题解就没有了。。。

线段树中插点权

维护一个巨大的线性基 最开始看代码没看懂GG


#include<cmath>#include<ctime>#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<algorithm>#include<iomanip>#include<vector>#include<string>#include<bitset>#include<queue>#include<map>#include<set>using namespace std;inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}void print(int x){if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}const int N=1010;int n,m;bitset<N>b,V[N],bas[N];char s[N];int last[N];struct seg_tree{vector<bitset<N> >b;vector<int>p;}tr[N<<2];void modify(int k,int l,int r,int x,int y,bitset<N> &val){if(l>=x&&r<=y){tr[k].b.push_back(val);return ;}int mid=(l+r)>>1;if(x<=mid)modify(k<<1,l,mid,x,y,val);if(y>mid)modify(k<<1|1,mid+1,r,x,y,val);}void solve(int k,int l,int r){register int i,j;for(i=0;i<tr[k].b.size();++i)for(j=1;j<N;++j)if(tr[k].b[i][j]){if(!bas[j][j]){bas[j]=tr[k].b[i];tr[k].p.push_back(j);break;}else tr[k].b[i]^=bas[j];}if(l==r){b.reset();for(i=1;i<N;++i)if(bas[i][i]&&!b[i])b^=bas[i];for(i=1;i<N;++i)if(b[i])break;if(i>=N)putchar('0');for(;i<N;++i)putchar(b[i]+'0');puts("");}else{int mid=(l+r)>>1;solve(k<<1,l,mid);solve(k<<1|1,mid+1,r);}for(i=0;i<tr[k].p.size();++i)bas[tr[k].p[i]].reset();}int main(){read();n=read();m=read();register int i,j,u,v,k;for(i=1;i<=m;++i){u=read();v=read();scanf("%s",s);if(u==v)continue;b.reset();k=strlen(s);for(j=0;j<k;++j)b[N-k+j]=s[j]-'0';if(last[u])modify(1,1,m,last[u],i-1,V[u]);if(last[v])modify(1,1,m,last[v],i-1,V[v]);last[u]=last[v]=i;V[u]^=b;V[v]^=b;}for(i=1;i<=n;++i)if(last[i])modify(1,1,m,last[i],m,V[i]);solve(1,1,m);return 0;}/*03 61 2 11 2 13 3 1111 3 1011011 2 10112 3 1110111 0 0101101101101110000*/

阅读全文
0 0
原创粉丝点击