帶修改線性基


最近模擬賽中有帶修線性基這個我 (聞所未聞 見所未見) 的黑科技。

我們仍未知道那天所見到的黑科技的名字

avatar
avatar

這道例題是動態加邊 每次詢問一個獨立集的最大權值。這里的權值定義為題目中的定義。

對於前兩個測試點 暴力枚舉選出了哪些點 然后判斷哪些邊可以用 通過這個暴力的操作可以發現 將邊的權值異或到點上 最后用點進行異或即可將那些不能使用的邊給異或掉。

於是可以發現這是一個選出若干個點使異或和最大的題目->線性基的題目。

觀察3,4,5測試點 無自環呈若干個聯通塊狀 每個連通塊最多只有一條邊 點權不帶修改 動態加入權值的線性基的題目。

剩下的測試點其實是 每次有兩個點的權值變化 在線維護線性基。

對於這種問題 一種比較粗暴的方法 是直接上線段樹分治維護線性基 記錄一下每次權值插入的線性基的位置然后方便撤銷。

復雜度\(mlog^2\cdot \frac{l}{w}\).(這個復雜度可能可以過 我也沒試過。

黑科技 在線維護帶修改線性基。

具體操作:

維護線性基的同時 再維護每線性基中每一個主元是由哪寫向量異或而成的。

修改其中的一個向量x的時候 找到由它異或而成的行中1的位數最低的那個行向量w(有零行選零行.

找到之后將其他被x異或過的向量 再一一異或一遍 因為此時我們把w當作x 此時w要被修改所以凡是異或過x的都要修改。

之所以選最小的是因為修改其他行向量的時候不會改變線性基的性質。

考慮一個向量原本不在線性基中被我們修改過后又可以存在於線性基中這種情況不存在 因為村子啊這種情況這個向量一定是零行 被優先選擇的 所以優先選擇了零行那么顯然 這種情況亦不存在。

我們再將w異或當前要異或的值 再插入線性基中即可。線性基的性質依舊保留 。復雜度\(\frac{nml}{w}\)

const int MAXN=510,maxn=1010;
int n,m,maxx;
int s[maxn];
bitset<maxn>b[MAXN],c[MAXN],w,ans;
char a[maxn];
inline void add(int x)
{
	fep(maxx,0,i)
	{
		if(b[x][i])
		{
			if(!s[i]){s[i]=x;break;}
			else
			{
				b[x]=b[x]^b[s[i]];
				c[x]=c[x]^c[s[i]];
				if(!b[x].any())return;
			}
		}
	}
}
inline void modify(int x)//尋找最小的被x xor的主元
{
	int ww=0;
	for(int i=1;i<=n;++i)if(c[i][x]&&!b[i].any()){ww=i;break;}
	if(!ww)rep(0,maxx,i)if(c[s[i]][x]&&s[i]){ww=s[i];s[i]=0;break;}
	rep(1,n,i)
		if(c[i][x]&&i!=ww)
		{
			b[i]=b[i]^b[ww];
			c[i]=c[i]^c[ww];
		}
	b[ww]^=w;add(ww);
}
int main()
{
	freopen("cut.in","r",stdin);
	freopen("cut.out","w",stdout);
	gt(n);gt(m);
	rep(1,n,i)c[i][i]=1;
	rep(1,m,i)
	{
		int x,y;
		gt(x);gt(y);
		scanf("%s",a);
		int len=strlen(a);--len;
		maxx=max(maxx,len);
		w.reset();
		fep(len,0,j)w[j]=a[len-j]-'0';
		modify(x);
		modify(y);
		int mark=0;
		ans.reset();
		fep(maxx,0,j)
		{
			if(!ans[j]&&s[j])ans^=b[s[j]];
			if(ans[j]||mark)
			{
				mark=1;
				printf("%d",ans[j]?1:0);
			}
		}
		if(!mark)printf("0");
		puts("");
	}
	return 0;
}

不過這個帶修是指異或的修改 如果是直接修改成某個值x呢?

可以發現我們轉成異或修改即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM