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