2019雅禮集訓 D5T1 matrix [字典樹]
阿新 • • 發佈:2019-01-10
題目描述:
樣例:
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)\),但我太菜了不敢寫。