4644: 经典傻逼题
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 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
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)
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;
}
/*
0
3 6
1 2 1
1 2 1
3 3 111
1 3 101101
1 2 1011
2 3 111011
1 0 0
101101
101101
110000
*/