• CF487E Tourists


    洛谷题面

    圆方树还真是个神奇的玩意儿……
    我们先考虑询问,对一个点双来说,经过这个点双的时候能走到的最小值肯定是这个点双内的最小值,那么只要对于每个点双把它的权值设成它里面所有点的最小值,那么就可以在建出广义圆方树之后用树链剖分求出路径最小值了
    然而这里有询问,一个想法是对每个点双开一个multiset,每次更改某一个点的值的时候就更改它在的所有点双,再维护即可
    于是出题人不说话并丢给了你一个菊花图
    菊花的话……根节点在所有的点双里(两个点也算一个点双),那么更改复杂度怕是要上天……
    然后接下来是一波骚操作:对于每个点双,我们不维护它的父亲节点的答案,那么查询的时候只要特判一下LCA是不是点双然后用它的父亲的权值更新一下。而且对于每一个修改,我们只要更新它的父亲点双的multiset就可以了
    于是总的复杂度为(O(nlog^2n))

    //minamoto
    #include<bits/stdc++.h>
    #define ll long long
    #define inf 0x3f3f3f3f
    #define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
    #define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
    #define go(T,u) for(register int i=T.head[u],v=T.e[i].v;i;i=T.e[i].nx,v=T.e[i].v)
    #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
    inline int max(const int &x,const int &y){return x>y?x:y;}
    inline int min(const int &x,const int &y){return x<y?x:y;}
    char buf[1<<21],*p1=buf,*p2=buf;
    using namespace std;
    int read(){
        int res,f=1;char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    inline char getop(){char ch;while((ch=getc())!='A'&&ch!='C');return ch;}
    char sr[1<<21],z[20];int C=-1,Z=0;
    inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    void print(int x){
        if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++C]=z[Z],--Z);sr[++C]='
    ';
    }
    const int N=5e5+5;
    struct eg{int v,nx;};
    struct node{
        eg e[N<<1];int head[N],tot;
        inline void add(int u,int v){
            e[++tot]={v,head[u]},head[u]=tot;
            e[++tot]={u,head[v]},head[v]=tot;
        }
    }G,T;multiset<int>s[N];
    int w[N],n,m,q,tot,x;
    int dfn[N],low[N],st[N],tim,stop;
    void tarjan(int u){
        dfn[u]=low[u]=++tim,st[++stop]=u;
        go(G,u){
            if(!dfn[v]){
                tarjan(v),low[u]=min(low[u],low[v]);
                if(low[v]>=dfn[u]){
                    T.add(++tot,u);
                    do{x=st[stop--],T.add(tot,x);}while(v!=x);
                }
            }else low[u]=min(low[u],dfn[v]);
        }
    }
    int t[N<<2];
    #define ls (p<<1)
    #define rs (p<<1|1)
    void update(int p,int l,int r,int x,int w){
        if(l==r)return (void)(t[p]=w);int mid=(l+r)>>1;
        x<=mid?update(ls,l,mid,x,w):update(rs,mid+1,r,x,w);
        t[p]=min(t[ls],t[rs]);
    }
    int query(int p,int l,int r,int ql,int qr){
        if(ql<=l&&qr>=r)return t[p];
        int res=inf,mid=(l+r)>>1;
        if(ql<=mid)res=min(res,query(ls,l,mid,ql,qr));
        if(qr>mid)res=min(res,query(rs,mid+1,r,ql,qr));
        return res;
    }
    int fa[N],dd[N],rk[N],sz[N],son[N],top[N],dep[N],num;
    void dfs1(int u){
        sz[u]=1,dep[u]=dep[fa[u]]+1;if(u<=n&&fa[u])s[fa[u]].insert(w[u]);
        go(T,u)if(v!=fa[u]){
            fa[v]=u,dfs1(v),sz[u]+=sz[v];
            if(sz[v]>sz[son[u]])son[u]=v;
        }
    }
    void dfs2(int u,int t){
        top[u]=t,dd[u]=++num,rk[num]=u;if(!son[u])return;
        dfs2(son[u],t);
        go(T,u)if(v!=fa[u]&&v!=son[u])dfs2(v,v);
    }
    int query(int u,int v){
        int res=inf;
        while(top[u]!=top[v]){
            if(dep[top[u]]<dep[top[v]])swap(u,v);
            res=min(res,query(1,1,tot,dd[top[u]],dd[u])),u=fa[top[u]];
        }if(dep[u]>dep[v])swap(u,v);
        res=min(res,query(1,1,tot,dd[u],dd[v]));
        return u<=n?res:min(res,w[fa[u]]);
    }
    void modify(int u,int ww){
        if(fa[u]){
            s[fa[u]].erase(s[fa[u]].find(w[u]));
            s[fa[u]].insert(ww);
            update(1,1,tot,dd[fa[u]],*s[fa[u]].begin());
        }w[u]=ww,update(1,1,tot,dd[u],ww);
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
        int u,v;
        tot=n=read(),m=read(),q=read(),w[0]=inf;
        fp(i,1,n)w[i]=read();
        fp(i,1,m)u=read(),v=read(),G.add(u,v);
        tarjan(1),dfs1(1),dfs2(1,1);
        fp(i,1,n)update(1,1,tot,dd[i],w[i]);
        fp(i,n+1,tot)update(1,1,tot,dd[i],*s[i].begin());
        char op;
        while(q--){
            op=getc(),u=read(),v=read();
            op=='C'?modify(u,v):print(query(u,v));
        }return Ot(),0;
    }
    
  • 相关阅读:
    c语言小项目---通讯录2.0
    小练习 打地鼠游戏
    4-20 这是一次失败的小项目 (单链表应用--通讯录)
    4-19 易错点 链表的插入
    小练习 简易双色球模拟器
    【2019.8.22】测试题目订正
    【模板】【P1182】数列分段II——二分答案
    【P2634】聪聪可可——点分治
    【模板】【P3605】【USACO17JAN】Promotion Counting 晋升者计数——动态开点和线段树合并(树状数组/主席树)
    【AcWing 113】【交互】特殊排序——二分
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10038442.html
Copyright © 2020-2023  润新知