zoukankan      html  css  js  c++  java
  • 【题解】CF487E Tourists

    CF487E Tourists

    写完这题已经完全自闭了 调了好久……

    题目大意

    就是求一张图中两点间所有路径中经过的点的最小值,带修。

    解法

    我们先考虑一下性质:对于无向图显然不好做,考虑一下咋转化成一棵树。

    那就往圆方树考虑呗,本题有啥性质?

    观察到:

    对于一个点双,必然存在一条路径走过该点双中的最小值。

    证明比较简单。由于点双内两点之间没有一个必经点,所以我们必定可以留出一个点从走过的那个最小值点再走出去。

    那么就考虑建立圆方树叭。码套路,先上一个 tarjan 找点双……

    细节1 注意点双的形成是需要满足 low[j]>=dfn[x] 的,不要犯傻打错了。

    好的,接下来怎么修改?考虑回答询问的同时其实也就能想到怎么维护修改:扔一个树剖就好了。

    那就考虑写树剖叭。码套路,先上两个 dfs ……

    细节2 注意树剖的 query 啥的别打错了……

    好嘞,上述准备工作都做好了,写个修改测样例……挂掉了。

    冷静分析:发现不论改方点还是圆点,都会影响到周围的点。

    怎么办,暴力修改?那显然不切实际,一个菊花图就可以卡爆你。

    继续考虑如何高效维护。我们知道,一个方点代表一个点双,那么,对于圆方树的树结构,每一个方点的答案其实除了它的孩子还要包含其父亲。这点也就恰好让维护变得不方便起来。

    那么我们不妨先考虑无视掉父亲的影响,只维护孩子,怎么做?

    维护一个 multiset 对每个方点,每次直接拿这个来暴力更新方点权值。

    好的,现在这里可以实现了,那带上父亲呢?

    冷静分析一波,这个父亲的影响需要满足两个条件:

    • 这个点是方点

    • 这个点的父亲没有被计算到

    那同时满足下列两个条件的点就只有可能是……

    最近公共祖先 ((LCA))

    所以对于每一组询问实际只有一个点需要被特殊对待!

    那么就直接做就好了。

    最后再附赠细节3:

    更新 low[x] 不要拿 low[j] 啊……(在不 dfs 的时候),调了好久……

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=200100;
    int head[N],tot,Head[N],tto,n,m,q,w[N];
    struct E {
    	int nxt,to;
    } e[N<<1],edge[N<<1];
    inline int read(){
    	int s=0;
    	char ch=getchar();
    	while(!isdigit(ch))ch=getchar();
    	while(isdigit(ch)){
    		s=s*10-'0'+ch;
    		ch=getchar();
    	} 
    	return s;
    }
    int nodepos,ddf,rk[N],cir[N],To[N];
    inline int Min(int x,int y) {return x<y?x:y;}
    multiset<int> S[N];
    inline void link(int x,int y,int w=0) {
    	if(w) {
    		edge[++tto]=(E) {
    			Head[x],y
    		};
    		Head[x]=tto;
    		return;
    	}
    	e[++tot]=(E) {
    		head[x],y
    	};
    	head[x]=tot;
    }
    int son[N],siz[N],dfn[N],low[N],st[N],top;
    int ttop[N],pa[N],dfstime,vis[N],dep[N];
    void dfs1(int x,int fa) {
    	siz[x]=1;
    	dep[x]=dep[fa]+1;
    	pa[x]=fa;
    	for(int i=Head[x]; i; i=edge[i].nxt) {
    		int j=edge[i].to;
    		if(j==fa)continue;
    		dfs1(j,x);
    		siz[x]+=siz[j];
    		if(siz[j]>siz[son[x]])son[x]=j;
    	}
    }
    void dfs2(int x,int t) {
    	rk[dfn[x]=++ddf]=x;
    	ttop[x]=t;
    	if(!son[x])return;
    	dfs2(son[x],t);
    	for(int i=Head[x]; i; i=edge[i].nxt) {
    		int j=edge[i].to;
    		if(j==son[x]||j==pa[x])continue;
    		dfs2(j,j);
    	}
    }
    void tarjan(int x,int root) {
    	dfn[x]=low[x]=++dfstime;
    	st[++top]=x;
    	if(x==root&&!head[x]) {
    		++nodepos;
    		To[nodepos]=x;
    		cir[x]=nodepos;
    		link(x,nodepos,1);
    		link(nodepos,x,1);
    		return;
    	}
    	int ch=0;
    	for(int i=head[x]; i; i=e[i].nxt) {
    		int j=e[i].to;
    		if(!dfn[j]) {
    			++ch;
    			tarjan(j,root);
    			low[x]=Min(low[x],low[j]);
    			if(dfn[x]<=low[j]&&x!=root)vis[x]=1;
    			if(x==root&&ch>1)vis[x]=1;
    			if(low[j]>=dfn[x]) {
    				int vex=-1;
    				++nodepos;
    				To[nodepos]=x;
    				do {
    					vex=st[top--];
    					cir[vex]=nodepos;
    					link(vex,nodepos,1);
    					link(nodepos,vex,1);
    				} while(vex!=j);
    				cir[x]=nodepos;
    				link(nodepos,x,1);
    				link(x,nodepos,1);
    			}
    		} else low[x]=Min(low[x],dfn[j]);
    	}
    }
    namespace SGT {
    	int mi[N<<2],ls[N<<2],rs[N<<2],node;
    	inline void pushup(int x) {
    		mi[x]=Min(mi[ls[x]],mi[rs[x]]);
    	}
    	void build(int &x,int l,int r) {
    		x=++node;
    		if(l==r) {
    			mi[x]=w[rk[l]];
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(ls[x],l,mid);
    		build(rs[x],mid+1,r);
    		pushup(x);
    	}
    	void change(int x,int L,int R,int pos,int v) {
    		if(L==R) {
    			mi[x]=v;
    			return;
    		}
    		int mid=(L+R)>>1;
    		if(pos<=mid)change(ls[x],L,mid,pos,v);
    		else change(rs[x],mid+1,R,pos,v);
    		pushup(x);
    	}
    	int query(int x,int L,int R,int l,int r) {
    		if(L>=l&&R<=r){return mi[x];} 
    		int mid=(L+R)>>1,res=(1LL<<60);
    		if(l<=mid)res=query(ls[x],L,mid,l,r);
    		if(mid<r)res=Min(res,query(rs[x],mid+1,R,l,r));
    		return res;
    	}
    }
    using namespace SGT;
    int rt;
    int Query(int u,int v) {
    	int res=(1LL<<60);
    	while(ttop[u]!=ttop[v]) {
    		if(dep[ttop[u]]<dep[ttop[v]])swap(u,v);
    		res=Min(res,query(rt,1,nodepos,dfn[ttop[u]],dfn[u]));
    		u=pa[ttop[u]];
    	}
    	if(dep[u]<dep[v])swap(u,v);
    	res=Min(res,query(rt,1,nodepos,dfn[v],dfn[u]));
    	if(dep[u]>dep[v])swap(u,v);
    	if(u>n)res=Min(res,w[pa[u]]);
    	return res;
    }
    void Change(int pos,int v) {
    	change(rt,1,nodepos,dfn[pos],v);
    	if(pos==1) {
    		w[pos]=v;
    		return;
    	}
    	int o=pa[pos];
    	S[o-n].erase(S[o-n].find(w[pos]));
    	S[o-n].insert(v);
    	int minv=*S[o-n].begin();
    	if(minv==w[o]){
    		w[pos]=v;
    		return;
    	}
    	change(rt,1,nodepos,dfn[o],minv);
    	w[o]=minv;
    	w[pos]=v;
    }
    inline void write(int x){
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    }
    signed main() {
    	freopen("in.txt","r",stdin);
    	n=read();m=read();q=read();
    	for(int i=1; i<=n; ++i)w[i]=read();
    	for(int i=1; i<=m; ++i) {
    		int u=read(),v=read();
    		link(u,v);
    		link(v,u);
    	}
    	nodepos=n;
    	tarjan(1,1);
    	memset(dfn,0,sizeof dfn);
    	dfs1(1,0);
    	dfs2(1,1);
    	for(int i=2; i<=n; ++i) {
    		S[pa[i]-n].insert(w[i]);
    	}
    	for(int i=n+1; i<=nodepos; ++i)
    		w[i]=(S[i-n].empty()?(1LL<<60):(*S[i-n].begin()));
    	memset(mi,0x7f,sizeof mi);
    	build(rt,1,nodepos);
    	while(q--) {
    		int u,v;
    		char opt;
    		cin>>opt;
    		u=read();v=read();
    		if(opt=='A') {
    			write(Query(u,v));
    			putchar('
    ');
    			continue;
    		}
    		Change(u,v);
    	}
    	return 0;
    }
    
  • 相关阅读:
    【Rust】结构体 struct
    【Rust】所有权、引用、借用
    Centos7升级glibc2.24
    ES用户权限控制
    PHP压缩html网页代码 : 清除空格,制表符,注释标记
    PHP通过HTTP_USER_AGENT判断是否为手机移动终端的函数
    php正则表达式替换URL链接地址为指定url的形式
    PHP下使用CURL方式POST数据至API接口的方法
    设计模式代理模式
    设计模式生成器模式
  • 原文地址:https://www.cnblogs.com/h-lka/p/15315107.html
Copyright © 2011-2022 走看看