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;
}
原文地址:https://www.cnblogs.com/bztMinamoto/p/10038442.html