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
HINT
前三条边加入之后的答案较为显然,考虑后三条边,加入第六条边之前, 考
虑点集{1,2},它对应的割只有第四条边, 因此答案就是第四条边的权值,考虑加
入最后一条边以后的情况,此时点集{1,2}对应的割变成了第四条边和第六条边组
成的集合,权值也发生了相应的改变。 点集{2}对应的割是第五条边和第六条边
组成的集合, 可以证明这就是权值最大的割,权值为1011(2) ⊕ 111011(2) =110000(2)
题解
弟弟地真实…
先把边的异或转到点上,每个点的权设为与它相连的边的异或和
然后就是一个带修改的线性基问题了
这类问题都可以用一种思想:线性基的删除只有在没有人能替代它的位置时删除
考虑线段树分治
单层修改回去的时候,显然上层不会有数能够让我这个被修改过的位置出现数,所以可以直接叉掉
然后就没了…
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);}
inline void pr2(int x){write(x);putchar('\n');}
const int MAXN=505;
const int MAXM=1005;
const int MAXL=1005;
bitset<MAXL> ad;
bitset<MAXL> pt[MAXN];int lst[MAXN];
bitset<MAXL> bit[MAXM*4][MAXM];
bitset<MAXL> lin[MAXL];int ok[MAXL];
bitset<MAXL> ans;
int cnt[MAXM*4];
int sta1[MAXM],sta2[MAXM],tp1,tp2;
int push()
{
for(int i=1000;i>=0;i--)if(ad[i])
{
if(!ok[i]){ok[i]=1,lin[i]=ad;return i;}
else ad=ad^lin[i];
}
return -1;
}
void in(int now)
{
for(int i=1;i<=cnt[now];i++)
{
ad=bit[now][i];int temp=push();
if(temp!=-1)sta2[++tp2]=temp;
}
sta1[++tp1]=tp2;
}
void ot()
{
int ls=sta1[--tp1];
while(tp2!=ls)ok[sta2[tp2--]]=0;
}
bool check()
{
for(int i=1000;i>=0;i--)
{
if(ad[i]==1&&ans[i]!=1)return true;
if(ad[i]!=1&&ans[i]==1)return false;
}
return false;
}
void solve()
{
ans.reset();
for(int i=1000;i>=0;i--)if(ok[i])
{
ad=ans^lin[i];
if(check())ans=ad;
}
bool ok1=false;
for(int i=1000;i>=0;i--)
{
if(!ans[i]&&ok1)pr1(0);
else if(ans[i])pr1(1),ok1=true;
}
if(!ok1)pr1(0);
puts("");
}
void insert(int now,int l,int r,int ql,int qr)
{
if(l==ql&&r==qr){bit[now][++cnt[now]]=ad;return ;}
int mid=(l+r)/2,lc=now<<1,rc=now<<1|1;
if(qr<=mid)insert(lc,l,mid,ql,qr);
else if(mid+1<=ql)insert(rc,mid+1,r,ql,qr);
else insert(lc,l,mid,ql,mid),insert(rc,mid+1,r,mid+1,qr);
}
void qry(int now,int l,int r)
{
in(now);
if(l==r){solve();ot();return ;}
int mid=(l+r)/2,lc=now<<1,rc=now<<1|1;
qry(lc,l,mid);
qry(rc,mid+1,r);
ot();
}
int n,m;
char ch[11000];
int main()
{
int T=read();
n=read();m=read();
for(int i=1;i<=m;i++)
{
int x=read(),y=read();scanf("%s",ch);int len=strlen(ch);
if(x==y)continue;
ans.reset();
for(int j=len-1;j>=0;j--)ans[len-j-1]=ch[j]-'0';
if(!lst[x]){pt[x]=ans;lst[x]=i;}
else
{
ad=pt[x];
insert(1,1,m,lst[x],i-1);
pt[x]^=ans;lst[x]=i;
}
if(!lst[y]){pt[y]=ans;lst[y]=i;}
else
{
ad=pt[y];
insert(1,1,m,lst[y],i-1);
pt[y]^=ans;lst[y]=i;
}
}
for(int i=1;i<=n;i++)if(lst[i])
{
ad=pt[i];
insert(1,1,m,lst[i],m);
}
qry(1,1,m);
// while(1);
return 0;
}