zoukankan      html  css  js  c++  java
  • 【CF487E】Tourists-圆方树+multiset+树链剖分

    测试地址:Tourists
    题目大意:一个n个点m条边的无向连通图,每个点有点权,要求维护单点修改,还有若干次询问,每次询问两个点之间的简单路径上的点权最小值最小是多少。
    做法:本题需要用到圆方树+multiset+树链剖分。
    做过APIO2018-铁人两项的同学应该很快能看出来,我们实际上就是要找一个中间点,使得这个中间点的点权最小,而能作为中间点的点我们在上面那题讨论过了:路径所经过的所有点双中的点。因此我们把圆方树建出来,并把点双的信息用multiset存在方点中,然后求路径最小值就是一个裸的树链剖分了。
    但是有一点要注意,如果是菊花图,那么单点修改可能会涉及到O(n)个点双,会爆,解决方法是每个点只对父亲方点有贡献,而在计算路径最小值时,如果LCA在方点上,再额外考虑它的父亲圆点即可。于是我们就以O(nlog2n)的时间复杂度解决了这一题。
    (这题是十几天前写的,然而怎么都调不出来,今天发现我学了假的圆方树后赶紧改了一下,交了一发就过了……假圆方树毁一生啊……)
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,q,w[200010];
    int first[200010]={0},firstt[200010]={0},tot=0;
    int tim=0,low[200010],dfn[200010],belong[200010]={0},totpbc;
    int st[200010],top=0;
    int fa[200010]={0},son[200010]={0},siz[200010],pos[200010],qpos[200010];
    int tp[200010]={0},dep[200010]={0},seg[800010];
    bool vis[200010]={0};
    struct edge
    {
        int v,next;
    }e[200010],t[200010];
    multiset<int> s[200010];
    multiset<int>::iterator it;
    
    void insert(edge *e,int *first,int a,int b)
    {
        e[++tot].v=b;
        e[tot].next=first[a];
        first[a]=tot;
    }
    
    void init()
    {
        scanf("%d%d%d",&n,&m,&q);
        for(int i=1;i<=n;i++)
            scanf("%d",&w[i]);
        for(int i=1;i<=m;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            insert(e,first,a,b);
            insert(e,first,b,a);
        }
        totpbc=n;
    }
    
    void tarjan(int v,int fa)
    {
        vis[v]=1;
        low[v]=dfn[v]=++tim;
        st[++top]=v;
        int now=top;
        for(int i=first[v];i;i=e[i].next)
            if (e[i].v!=fa)
            {
                if (!vis[e[i].v])
                {
                    tarjan(e[i].v,v);
                    low[v]=min(low[v],low[e[i].v]);
                    if (low[e[i].v]>=dfn[v])
                    {
                        totpbc++;
                        insert(t,firstt,v,totpbc);
                        do
                        {
                            insert(t,firstt,totpbc,st[top]);
                            s[totpbc].insert(w[st[top]]);
                            belong[st[top]]=totpbc;
                        }while(st[top--]!=e[i].v);
                        w[totpbc]=*(s[totpbc].begin());
                    }
                }
                else low[v]=min(low[v],dfn[e[i].v]);
            }
    }
    
    void dfs1(int v)
    {
        siz[v]=1;
        int mxsiz=0;
        for(int i=firstt[v];i;i=t[i].next)
        {
            fa[t[i].v]=v;
            dep[t[i].v]=dep[v]+1;
            dfs1(t[i].v);
            if (siz[t[i].v]>mxsiz)
            {
                mxsiz=siz[t[i].v];
                son[v]=t[i].v;
            }
            siz[v]+=siz[t[i].v];
        }
    }
    
    void dfs2(int v,int top)
    {
        pos[v]=++tim;
        qpos[tim]=v;
        tp[v]=top;
        if (son[v]) dfs2(son[v],top);
        for(int i=firstt[v];i;i=t[i].next)
            if (t[i].v!=son[v]) dfs2(t[i].v,t[i].v);
    }
    
    void buildtree(int no,int l,int r)
    {
        if (l==r)
        {
            seg[no]=w[qpos[l]];
            return;
        }
        int mid=(l+r)>>1;
        buildtree(no<<1,l,mid);
        buildtree(no<<1|1,mid+1,r);
        seg[no]=min(seg[no<<1],seg[no<<1|1]);
    }
    
    void segmodify(int no,int l,int r,int x,int d)
    {
        if (l==r)
        {
            seg[no]=d;
            return;
        }
        int mid=(l+r)>>1;
        if (x<=mid) segmodify(no<<1,l,mid,x,d);
        else segmodify(no<<1|1,mid+1,r,x,d);
        seg[no]=min(seg[no<<1],seg[no<<1|1]);
    }
    
    int segquery(int no,int l,int r,int s,int t)
    {
        if (l>=s&&r<=t) return seg[no];
        int ret=1000000000,mid=(l+r)>>1;
        if (s<=mid) ret=min(ret,segquery(no<<1,l,mid,s,t));
        if (t>mid) ret=min(ret,segquery(no<<1|1,mid+1,r,s,t));
        return ret;
    }
    
    void modify(int x,int y)
    {
        if (belong[x])
        {
            it=s[belong[x]].find(w[x]);
            s[belong[x]].erase(it);
        }
        w[x]=y;
        segmodify(1,1,totpbc,pos[x],y);
        if (belong[x])
        {
            s[belong[x]].insert(w[x]);
            w[belong[x]]=*(s[belong[x]].begin());
            segmodify(1,1,totpbc,pos[belong[x]],w[belong[x]]);
        }
    }
    
    int query(int x,int y)
    {
        int ret=1000000000;
        while(tp[x]!=tp[y])
        {
            if (dep[tp[x]]<dep[tp[y]]) swap(x,y);
            ret=min(ret,segquery(1,1,totpbc,pos[tp[x]],pos[x]));
            x=fa[tp[x]];
        }
        if (dep[x]>dep[y]) swap(x,y);
        ret=min(ret,segquery(1,1,totpbc,pos[x],pos[y]));
        if (x>n&&fa[x]) ret=min(ret,w[fa[x]]);
        return ret;
    }
    
    void work()
    {
        for(int i=1;i<=q;i++)
        {
            char s[3];
            int x,y;
            scanf("%s%d%d",s,&x,&y);
            if (s[0]=='C') modify(x,y);
            else printf("%d
    ",query(x,y));
        }
    }
    
    int main()
    {
        init();
        tot=0;
        tarjan(1,0);
        dfs1(1);
        tim=0;
        dfs2(1,1);
        buildtree(1,1,totpbc);
        work();
    
        return 0;
    }
  • 相关阅读:
    使用parted 对大容量盘进行分区
    CENTOS7 修改网卡名称为eth[012...],格式
    docker报错
    docker 存储定义成direct-lvm 模式
    Docker存储方式选型建议
    centos install docker setup centos7 安装docker
    docker centos yum 源
    zip 解压脚本
    IaaS,PaaS,Saas 云服务的介绍
    Codeforces Round #589 (Div. 2) D. Complete Tripartite(模拟)
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793320.html
Copyright © 2011-2022 走看看