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

猜你喜欢

转载自www.cnblogs.com/p-b-p-b/p/10252429.html