其他分享
首页 > 其他分享> > BZOJ 2001: [Hnoi2010]City 城市建设

BZOJ 2001: [Hnoi2010]City 城市建设

作者:互联网

好鬼的CDQ分治,感觉复杂度好迷的说感觉就是个剪枝的暴力

首先看到题目,动态MST,妈妈我会线段树分治+LCT然后这题就做完了

大体上很套路,我们把修改看作一条边的删除以及一条新边的加入,就可以求出每条边出现的时间区间

然后按时间为下标建线段树,我们只要能实现插入一条边/撤销即可,然后我们发现这个东西可以很容易LCT维护,每次找出成环的路径上的最大值然后替换掉即可

总体复杂度\(O(n\log^2 n)\),据说常数巨大(我不想写),因此这里讲一种抄来的玄学CDQ分治的做法

首先我们要明确CDQ的本质:讲可以一些操作间重复的部分最大化,然后解决这个重复部分

考虑我们现在处理的区间是\([l,r]\),那么对于不被这个区间操作影响的边(姑且称为静态边),显然我们可以找出其中一些必须选的边和一些肯定不选的边,然后再往下递归的时候就不用考虑它们

那具体怎么处理呢,我们考虑进行以下操作:

  1. 将现在分治的区间内的所有边(姑且称为动态边),边权设为\(-\infty\),然后跑一遍MST,然后我们找出MST上的所有静态边(边权不为\(-\infty\)),它们显然是必选的
  2. 将现在分治的区间内的所有边,边权设为\(\infty\),然后跑一遍MST,然后我们找出没有出现在MST上的所有静态边(边权不为\(\infty\)),它们显然是无用的

然后我们把所有的必选边先连起来,然后往下处理的时候忽略掉无用边

根据某种神奇的力量(或者感性理解),这样每次处理的边数会减半(会证明的老哥麻烦告诉我下证明),因此总复杂度就是\(O(n\log^2 n)\)的,但是常数极小(分治+排序),不像某两大常数算法的结合

#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
#define RI register int
#define CI const int&
#define Tp template <typename T>
#define pb push_back
using namespace std;
typedef long long LL;
const int N=50005,INF=1e9;
struct edge
{
    int x,y,w,id;
    friend inline bool operator < (const edge& A,const edge& B)
    {
        return A.w<B.w;
    }
}ne[N],tp[N],nw; vector <edge> E[20]; int n,m,q,val[N],px[N],py[N],pos[N]; LL ans[N];
class FileInputOutput
{
    private:
        static const int S=1<<21;
        #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
        #define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
        char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[25];
    public:
        inline FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
        Tp inline void read(T& x)
        {
            x=0; char ch; while (!isdigit(ch=tc()));
            while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
        }
        Tp inline void write(T x)
        {
            RI ptop=0; while (pt[++ptop]=x%10,x/=10);
            while (ptop) pc(pt[ptop--]+48); pc('\n');
        }
        inline void flush(void)
        {
            fwrite(Fout,1,Ftop-Fout,stdout);
        }
        #undef tc
        #undef pc
}F;
class UnionFindSet
{
    private:
        int fa[N];
    public:
        inline void init(CI n,edge *e)
        {
            for (RI i=0;i<n;++i) fa[e[i].x]=e[i].x,fa[e[i].y]=e[i].y;
        }
        inline int getfa(CI x)
        {
            return fa[x]!=x?fa[x]=getfa(fa[x]):x;
        }
        inline bool identify(CI x,CI y)
        {
            return getfa(x)==getfa(y);
        }
        inline void Union(CI x,CI y)
        {
            fa[getfa(x)]=getfa(y);
        }
}UFS;
inline void retain(int& n,LL& sum)
{
    RI i,cnt=0; for (UFS.init(n,ne),sort(ne,ne+n),i=0;i<n;++i)
    if (!UFS.identify(ne[i].x,ne[i].y)) UFS.Union(ne[i].x,ne[i].y),tp[cnt++]=ne[i];
    for (UFS.init(cnt,tp),i=0;i<cnt;++i) if (tp[i].w!=-INF)
    if (!UFS.identify(tp[i].x,tp[i].y)) UFS.Union(tp[i].x,tp[i].y),sum+=tp[i].w;
    for (cnt=i=0;i<n;++i) if (!UFS.identify(ne[i].x,ne[i].y))
    tp[cnt++]=(edge){UFS.getfa(ne[i].x),UFS.getfa(ne[i].y),ne[i].w,ne[i].id};
    for (i=0;i<cnt;++i) pos[ne[i].id]=i,ne[i]=tp[i]; n=cnt;
}
inline void remove(int& n)
{
    RI i,cnt=0; for (UFS.init(n,ne),sort(ne,ne+n),i=0;i<n;++i)
    if (!UFS.identify(ne[i].x,ne[i].y)) UFS.Union(ne[i].x,ne[i].y),tp[cnt++]=ne[i];
    else if (ne[i].w==INF) tp[cnt++]=ne[i];
    for (i=0;i<cnt;++i) pos[ne[i].id]=i,ne[i]=tp[i]; n=cnt;
}
inline void solve(CI l=1,CI r=q,CI dep=0,LL sum=0)
{
    int n=E[dep].size(); RI i; if (l==r) val[px[l]]=py[l];
    for (i=0;i<n;++i) E[dep][i].w=val[E[dep][i].id],ne[i]=E[dep][i],pos[ne[i].id]=i;
    if (l==r)
    {
        for (ans[l]=sum,UFS.init(n,ne),sort(ne,ne+n),i=0;i<n;++i)
        if (!UFS.identify(ne[i].x,ne[i].y)) UFS.Union(ne[i].x,ne[i].y),ans[l]+=ne[i].w; return;
    }
    for (i=l;i<=r;++i) ne[pos[px[i]]].w=-INF; retain(n,sum);
    for (i=l;i<=r;++i) ne[pos[px[i]]].w=INF; remove(n);
    for (E[dep+1].clear(),i=0;i<n;++i) E[dep+1].pb(ne[i]);
    int mid=l+r>>1; solve(l,mid,dep+1,sum); solve(mid+1,r,dep+1,sum);
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    RI i; for (F.read(n),F.read(m),F.read(q),i=1;i<=m;++i)
    F.read(nw.x),F.read(nw.y),F.read(nw.w),val[i]=nw.w,nw.id=i,E[0].pb(nw);
    for (i=1;i<=q;++i) F.read(px[i]),F.read(py[i]);
    for (solve(),i=1;i<=q;++i) F.write(ans[i]); return F.flush(),0;
}

标签:City,分治,const,int,MST,然后,Hnoi2010,include,2001
来源: https://www.cnblogs.com/cjjsb/p/12260586.html