1. 程式人生 > >[bzoj4644][線性基][線段樹分治]經典傻逼題

[bzoj4644][線性基][線段樹分治]經典傻逼題

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;
}