题目描述:
样例:
input:
2 2
1 1 1 2
output:
11
数据范围与约定:
标签:字典树
嗯……这题我还是有些懵逼……
大概意思就是枚举左端点,利用上一次的字典树得到当前的字典树。
每个节点里存儿子的编号、哪些行在这里出现过,以及当前节点对答案的贡献。贡献在每次新加入一行时可以利用哪些行在这里出现过的信息(即代码中的set)更新。
合并时启发式合并,并抹去其中一个节点的贡献。
最后由于根节点没有实际意义,将根节点的贡献也抹去。
如果还不懂可以结合代码理解。
#include<bits/stdc++.h>
namespace my_std{
using namespace std;
#define mod 998244353
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define sz 500505
typedef long long ll;
template<typename T>
inline void read(T& t)
{
t=0;char f=0,ch=getchar();
double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.')
{
ch=getchar();
while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();
}
t=(f?-t:t);
}
template<typename T,typename... Args>
inline void read(T& t,Args&... args){read(t); read(args...);}
void file()
{
#ifndef ONLINE_JUDGE
freopen("a.txt","r",stdin);
#endif
}
inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
int n,m;
int rt=1,cnt=1;
ll ans,now;
struct hh
{
ll val;
map<int,int>ch;
set<int>s;
void insert(int i)
{
int x=i,y=n-x+1;
auto it=s.insert(i).fir;
if (it!=s.begin()) x=i-*prev(it);
if (next(it)!=s.end()) y=*next(it)-i;
val+=1ll*x*y;now+=1ll*x*y;
}
}a[sz];
int merge(int x,int y)
{
if (!x||!y) return x+y;
if (a[x].ch.size()<a[y].ch.size()) swap(x,y);
for (auto i:a[y].ch) a[x].ch[i.fir]=merge(a[x].ch[i.fir],i.sec);
if (a[x].s.size()<a[y].s.size()) swap(a[x].s,a[y].s),swap(a[x].val,a[y].val);
for (auto i:a[y].s) a[x].insert(i);
now-=a[y].val;
return x;
}
int work()
{
int x;
read(n,m);
rep(i,1,n)
{
int cur=rt;
rep(j,1,m)
{
read(x);
if (!a[cur].ch[x]) a[cur].ch[x]=++cnt;
cur=a[cur].ch[x];a[cur].insert(i);
}
}
ans+=now;
rep(i,2,m)
{
int newrt=0;
for (auto j:a[rt].ch)
newrt=merge(newrt,j.sec);
now-=a[rt=newrt].val;
ans+=now;
}
cout<<ans;
return 0;
}
int Work=(file(),work());
int main(){return Work;}
p.s.据说把set换成splay可以做到\(O(nmlogn)\),但我太菜了不敢写。