1. 程式人生 > >2019雅禮集訓 D5T1 matrix [字典樹]

2019雅禮集訓 D5T1 matrix [字典樹]

題目描述:

樣例:

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)\),但我太菜了不敢寫。