zoukankan      html  css  js  c++  java
  • Luogu P5168 xtq玩魔塔

    这题不错啊,结合了一些不太传统的姿势。

    首先看到题目有一问从一个点到另一个点边权最小值。想到了什么?

    克鲁斯卡尔生成树+倍增?好吧其实有一个更常用NB的算法叫克鲁斯卡尔重构树

    (不会的可以看dalao's blog,并且可以尝试切掉Luogu P4768 [NOI2018]归程

    回到这题,我们可以把重构树建出来之后直接求两点LCA的权值。

    然后对于第三问,考虑继续利用重构树,我们发现此时能走到的点在树上一定是一颗子树。

    子树内DFS序连续啊,所以就变成区间数颜色了,直接莫队啊!

    好吧还有修改,那就带修莫队,在数据随机的情况下稳如老狗。

    然后这题就完了,不过有一个细节就是克鲁斯卡尔重构树的父节点权值一定大于子节点,所以不用在向上跳的时候再维护一个最大值数组。

    CODE

    #include<cstdio>
    #include<cctype>
    #include<cmath>
    #include<algorithm>
    #define RI register int
    #define Tp template <typename T>
    using namespace std;
    const int N=100005;
    struct data
    {
        int x,y,val;
        inline friend bool operator <(data A,data B)
        {
            return A.val<B.val;
        }
    }a[N*3]; int n,m,s,opt,x,y,z,ans[N<<1],rst[N*3],dfn[N<<1],blk[N];
    struct ques
    {
        int l,r,id,t;
        inline ques (int L=0,int R=0,int Id=0,int T=0)
        {
            l=L; r=R; id=Id; t=T;
        }
        inline friend bool operator <(ques A,ques B)
        {
            return blk[A.l]!=blk[B.l]?blk[A.l]<blk[B.l]:(blk[A.r]!=blk[B.r]?blk[A.r]<blk[B.r]:A.t<B.t);
        }
    }q[N<<1]; int cnt_q,cnt_cm,cnt_col,bkt[N*3],tot,d[N<<1],sze[N<<1];
    struct operation
    {
        int pos,col;
        inline operation(int Pos=0,int Col=0) { pos=Pos; col=Col; }
    }p[N<<1]; int cnt_p,col[N],now,L=1,R,list[N],ret,size;
    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<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
            char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
        public:
            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)
            {
                if (!x) return (void)(pc('0'),pc('
    ')); RI ptop=0;
                while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('
    ');
            }
            inline void Fend(void)
            {
                fwrite(Fout,1,Ftop,stdout);
            }
    }F;
    inline void swap(int &x,int &y)
    {
        int t=x; x=y; y=t;
    }
    class Double_Increased_On_Tree
    {
        private:
            static const int P=18;
            struct edge
            {
                int to,nxt;
            }e[N<<1]; int head[N<<1],cnt,idx,anc[N<<1][P],dep[N<<1];
            inline void reset(int now)
            {
                for (RI i=0;i<P-1;++i) if (anc[now][i])
                anc[now][i+1]=anc[anc[now][i]][i]; else break;
            }
            inline void miner(int &x,int y)
            {
                if (y<x) x=y;
            }
        public:
            inline void add(int x,int y)
            {
                e[++cnt]=(edge){y,head[x]},head[x]=cnt;
            }
            #define to e[i].to
            inline void DFS(int now)
            {
                if (now<=n) list[dfn[now]=++idx]=now,sze[now]=1;
                else dfn[now]=1e9;reset(now); for (RI i=head[now];i;i=e[i].nxt)
                anc[to][0]=now,dep[to]=dep[now]+1,DFS(to),sze[now]+=sze[to],miner(dfn[now],dfn[to]);
            }
            #undef to
            inline int getLCA(int x,int y)
            {
                RI i; if (dep[x]<dep[y]) swap(x,y); for (i=P-1;~i;--i)
                if (dep[anc[x][i]]>=dep[y]) x=anc[x][i]; if (x==y) return x;
                for (i=P-1;~i;--i) if (anc[x][i]!=anc[y][i])
                x=anc[x][i],y=anc[y][i]; return anc[x][0];
            }
            inline int getinterval(int x,int y)
            {
                for (RI i=P-1;~i;--i)if (anc[x][i]&&d[anc[x][i]]<=y) x=anc[x][i]; return x;
            }
    }T;
    class Kruskal_Rubuild_Tree_Solver
    {
        private:
            int father[N<<1];
            inline int getfather(int x)
            {
                return father[x]^x?father[x]=getfather(father[x]):x;
            }
        public:
            inline void init(void)
            {
                for (RI i=1;i<=n;++i) father[i]=i;
            }
            inline void Kruskal(void)
            {
                sort(a+1,a+m+1); init(); for (RI i=1;i<=m;++i)
                if ((a[i].x=getfather(a[i].x))!=(a[i].y=getfather(a[i].y)))
                {
                    d[++tot]=a[i].val; father[a[i].x]=father[a[i].y]=tot;
                    T.add(tot,a[i].x); T.add(tot,a[i].y); father[tot]=tot;
                }
            }
    }K;
    inline void add(int col)
    {
        if (++bkt[col]==1) ++ret;
    }
    inline void del(int col)
    {
        if (--bkt[col]==0) --ret;
    }
    inline void travel(int now)
    {
        if (p[now].pos>=L&&p[now].pos<=R) del(col[list[p[now].pos]]),
        add(p[now].col); swap(p[now].col,col[list[p[now].pos]]);
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        RI i; for (F.read(n),F.read(m),F.read(s),i=1;i<=n;++i)
        F.read(col[i]),rst[++cnt_col]=col[i]; for (i=1;i<=m;++i)
        F.read(a[i].x),F.read(a[i].y),F.read(a[i].val);
        for (tot=n,K.Kruskal(),T.DFS(tot),i=1;i<=s;++i)
        {
            F.read(opt); F.read(x); F.read(y);
            switch (opt)
            {
                case 1:
                    p[++cnt_p]=operation(dfn[x],y); rst[++cnt_col]=y; break;
                case 2:
                    ans[++cnt_q]=d[T.getLCA(x,y)]; break;
                case 3:
                    int top=T.getinterval(x,y);	q[++cnt_cm]=ques(dfn[top],dfn[top]+sze[top]-1,++cnt_q,cnt_p); break;
            }
        }
        sort(rst+1,rst+cnt_col+1); cnt_col=unique(rst+1,rst+cnt_col+1)-rst-1;
        for (i=1;i<=n;++i) col[i]=lower_bound(rst+1,rst+cnt_col+1,col[i])-rst;
        for (i=1;i<=cnt_p;++i) p[i].col=lower_bound(rst+1,rst+cnt_col+1,p[i].col)-rst;
        for (size=(int)pow(n,2.0/3.0),i=1;i<=n;++i) blk[i]=(i-1)/size+1;
        for (sort(q+1,q+cnt_cm+1),i=1;i<=cnt_cm;++i)
        {
            while (now<q[i].t) travel(++now); while (now>q[i].t) travel(now--);
            while (L>q[i].l) add(col[list[--L]]); while (R<q[i].r) add(col[list[++R]]);
            while (L<q[i].l) del(col[list[L++]]); while (R>q[i].r) del(col[list[R--]]);
            ans[q[i].id]=ret;
        }
        for (i=1;i<=cnt_q;++i) F.write(ans[i]); return F.Fend(),0;
    }
    
  • 相关阅读:
    小白的springboot之路(三)、集成mybatis与MySQL
    小白的springboot之路(四)、mybatis-generator自动生成mapper和model、dao
    springboot打印SQL及多环境配置
    小白的springboot之路(二)、集成swagger
    小白的springboot之路(一)、环境搭建、第一个实例
    npm切换成淘宝镜像源
    无废话设计模式(0)--设计模式的六大原则
    java之--加密、解密算法
    【Java】Java中的final关键字和static
    Add an Action that Displays a Pop-up Window 添加显示弹出窗口按钮
  • 原文地址:https://www.cnblogs.com/cjjsb/p/10235332.html
Copyright © 2011-2022 走看看