Winter Camp 2019 Simulation Day5 T1 Matrix(Trie树合并)

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/86253356

在这里插入图片描述在这里插入图片描述有位大佬把 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);
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/86253356