BZOJ 3681: Arietta

数据结构优化建图的网络流,还需要Dsu on tree可持久化,但也不大难写

很容易想出暴力的做法,把操作和音符看作二分图,然后就是求一个最大匹配,转化一下就是一个最大流

此时的边数目是\(O(nm)\)的,显然需要优化边数

树上子树内信息的维护般就那么几种,这里DFS+主席树上树无法维护(因为颜色不是可减的),那么我们考虑静态科技Dsu on tree

这道题里面我们要给每个点开可持久化线段树,线段树的下标是颜色,这样可以实现某个点子树内的连边操作

那么怎么维护呢,根据Dsu on tree的思想,我们做到一个点时就把它重儿子的线段树继承过来,然后暴力把轻儿子一个一个加进去

由于Dsu on tree的复杂度是\(O(n\log n)\)的(每个点做为轻儿子的次数是\(\log\)级别的),线段树每次新建\(\log n\)个节点,因此总边数是\(O(n\log^2 n)\)

然后跑一跑网络流就好了,根据Dinic跑二分图的效率以及网络流跑不满的特性可以卡过此题

PS:这题又卡时间又卡内存,可谓毒瘤至极

#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=10005,INF=1e9;
struct edge
{
    int to,nxt,v;
}e[N]; int n,m,cnt,head[N],x,a[N],rt[N],size[N],son[N],l,r,t,tot,lst,cur; 
inline void addedge(CI x,CI y)
{
    e[++cnt]=(edge){y,head[x],0}; head[x]=cnt;
}
#define to e[i].to
namespace NF //Network Flow
{
    const int N=1300005,M=2500005;
    edge e[M]; int cnt=1,head[N],cur[N],q[N],dep[N],s,t;
    inline void addedge(CI x,CI y,CI z)
    {
        e[++cnt]=(edge){y,head[x],z}; head[x]=cnt;
        e[++cnt]=(edge){x,head[y],0}; head[y]=cnt;
    }
    inline bool BFS(void)
    {
        RI H=0,T=1; memset(dep,0,t+1<<2); q[dep[s]=1]=s;
        while (H<T)
        {
            int now=q[++H]; for (RI i=head[now];i;i=e[i].nxt)
            if (e[i].v&&!dep[to]) dep[to]=dep[now]+1,q[++T]=to;
        }
        return dep[t];
    }
    inline int DFS(CI now,CI tar,int dis)
    {
        if (now==tar) return dis; int ret=0;
        for (RI& i=cur[now];i&&dis;i=e[i].nxt)
        if (e[i].v&&dep[to]==dep[now]+1)
        {
            int dist=DFS(to,tar,min(dis,e[i].v));
            dis-=dist; ret+=dist; e[i].v-=dist; e[i^1].v+=dist;
        }
        if (!ret) dep[now]=0; return ret;
    }
    inline int Dinic(int ret=0)
    {
        while (BFS()) memcpy(cur,head,t+1<<2),ret+=DFS(s,t,INF); return ret;
    }
};
class Segment_Tree
{
    private:
        static const int N=1300005;
        struct segment
        {
            int ch[2];
        }node[N];
    public:
        #define lc(x) node[x].ch[0]
        #define rc(x) node[x].ch[1]
        #define TN CI l=1,CI r=n
        inline void insert(CI lst,int& now,CI pos,CI id,TN)
        {
            node[now=++tot]=node[lst]; if (lst) NF::addedge(now,lst,INF);
            if (l==r) return NF::addedge(now,id,INF); int mid=l+r>>1;
            if (pos<=mid) insert(lc(lst),lc(now),pos,id,l,mid);
            else insert(rc(lst),rc(now),pos,id,mid+1,r);
        }
        inline void link(CI now,CI beg,CI end,CI id,TN)
        {
            if (!now) return; if (beg<=l&&r<=end) return NF::addedge(id,now,INF); int mid=l+r>>1;
            if (beg<=mid) link(lc(now),beg,end,id,l,mid); if (end>mid) link(rc(now),beg,end,id,mid+1,r);
        }
        inline void relink(void)
        {
            for (RI i=n+1;i<=tot;++i)
            {
                if (lc(i)) NF::addedge(i,lc(i),INF);
                if (rc(i)) NF::addedge(i,rc(i),INF);
            }
        }
        #undef lc
        #undef rc
        #undef TN
}SEG;
inline void expand(CI now)
{
    SEG.insert(lst,cur,a[now],now); lst=cur;
    for (RI i=head[now];i;i=e[i].nxt) expand(to);
}
inline void DFS1(CI now=1)
{
    size[now]=1; int mx=0; for (RI i=head[now];i;i=e[i].nxt)
    DFS1(to),size[now]+=size[to],size[to]>mx&&(mx=size[to],son[now]=to);
}
inline void DFS2(CI now=1)
{
    RI i; for (i=head[now];i;i=e[i].nxt) DFS2(to);
    lst=rt[son[now]]; SEG.insert(lst,cur,a[now],now); lst=cur;
    for (i=head[now];i;i=e[i].nxt) if (to!=son[now]) expand(to); rt[now]=lst;
}
#undef to
int main()
{
    RI i; for (scanf("%d%d",&n,&m),i=2;i<=n;++i) scanf("%d",&x),addedge(x,i);
    for (tot=n,i=1;i<=n;++i) scanf("%d",&a[i]); DFS1(); DFS2(); SEG.relink();
    for (NF::s=tot+m+1,NF::t=tot+m+2,i=1;i<=n;++i) NF::addedge(i,NF::t,1);
    for (i=1;i<=m;++i) scanf("%d%d%d%d",&l,&r,&x,&t),
    NF::addedge(NF::s,tot+i,t),SEG.link(rt[x],l,r,tot+i);
    return printf("%d",NF::Dinic()),0;
}
posted @ 2020-01-30 22:56  空気力学の詩  阅读(140)  评论(0编辑  收藏  举报