1. 程式人生 > >Winter Camp 2019 Simulation Day5 T1 Matrix(Trie樹合併)

Winter Camp 2019 Simulation Day5 T1 Matrix(Trie樹合併)

在這裡插入圖片描述在這裡插入圖片描述有位大佬把 n 2 m n^2m m 2

n m^2n 打了個拼盤然後拿了90分%%%
正解以前完全沒意識過。
把每一行看做一個字串加入trie樹,然後就可以用做字串題的方法來做這道題,具體就是先把矩陣的左邊界看做是1,求出每個字串在哪幾行出現,那麼就可以統計出有多少個行區間包含這個字串,又每個字串確定了矩形的長,那麼trie樹中每個點行區間的個數就是方案數。
把左邊界右移的時候,(居然)可以把根的所有兒子合併,trie樹合併和線段樹合併差不多,然後用set的啟發式合併繼續維護左端點右移後的每個字串在哪幾行出現,之後就這樣。
複雜度 O
( n m log 2 n ) O(nm \log^2 n)

PS:可以用Splay代替set做到一個 log \log 但是我個人。。。。。。不想打。

AC Code:

#include<bits/stdc++.h>
#define maxn 500005
#define LL long long
using namespace std;

int n,m;
struct mat{ int f[maxn*2];int* operator[](int x){ return f+x*m; } }A;

int rt,tot;
LL val[maxn],sum,ans;
set<int>st[maxn];
map<int,int>mp[maxn];

set<int>::iterator prev(set<int>::iterator it)
{
	it--;
	return it;
}
void Insert(int id,int x)
{
	int Llen = x , Rlen = n-x+1;
	set<int>::iterator it = st[id].lower_bound(x);
	if(it!=st[id].begin()) 
		Llen = x - *prev(it);
	if(it!=st[id].end()) 
		Rlen = *it - x;
	st[id].insert(x);
	val[id] += 1ll * Llen * Rlen;
	sum += 1ll* Llen * Rlen;
}

void Merge(int &now,int lc,int rc)
{
	if(!lc || !rc) {now = lc+rc; return;}
	if(mp[lc].size() < mp[rc].size()) swap(lc,rc);
	for(map<int,int>::iterator it = mp[rc].begin();it!=mp[rc].end();it++)
		Merge(mp[lc][(*it).first],mp[lc][(*it).first],(*it).second);
	if(st[lc].size() < st[rc].size())
	{
		swap(st[lc],st[rc]);
		swap(val[lc],val[rc]);
	}
	for(set<int>::iterator it=st[rc].begin();it!=st[rc].end();it++)
		Insert(lc,*it);
		
	sum -= val[rc];
	now = lc;
}

int main()
{
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	
	scanf("%d%d",&n,&m);
	int tot = 0;
	for(int i=1;i<=n;i++)
		for(int j=1,p=rt;j<=m;j++)
		{
			scanf("%d",&A[i][j]);
			if(!mp[p].count(A[i][j])) mp[p][A[i][j]] = ++tot;
			p = mp[p][A[i][j]];
			Insert(p,i);
		}
		
	ans += sum;
	for(int i=1;i<m;i++)
	{
		int nrt = -1;
		for(map<int,int>::iterator it = mp[rt].begin() ; it!=mp[rt].end() ; it++)
		{
			if(nrt == -1) 
				nrt = (*it).second;
			else 
				Merge(nrt,nrt,(*it).second);
		}
		sum -= val[nrt];		
		ans += sum;
		rt = nrt;
	}
	printf("%lld\n",ans);
}