关于圆方树
  • 板块CF487E Tourists
  • 楼主FxorG
  • 当前回复7
  • 已保存回复7
  • 发布时间2021/8/10 14:01
  • 上次更新2023/11/4 11:11:58
查看原帖
关于圆方树
125901
FxorG楼主2021/8/10 14:01

RT 我用方点表示整个点双的最小值 并开个 multiset 维护 但是 2 种我认为都对的写法,写法1错,写法2对。

写法一是在找到点双的时候就把全部的 val 插入 multiset

写法二是在树剖 dfs1 时判断父亲是否是方点 是的话就将当前的 val 插入父亲

为什么第一种是错的?这两种的区别应该就是一个点能否对多个 multiset 贡献吧

感谢!

注释有标明

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define ll long long

using namespace std;
int rd() {
	int f=1,sum=0; char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return sum*f;
}
ll lrd() {
	ll f=1,sum=0; char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return sum*f;
}
/*
建圆方树 方点的权值是整个双联通的最小值
*/ 

const int N=(int)(2e5+5),inf=0x3f3f3f3f;
multiset<int>S[N];
int val[N],fa[N],fang_tot;
int dep[N],sz[N],son[N],top[N],id[N],rk[N],sp_tot;
int n,m,Q;
struct edge {
	int nex,to;
};
struct GRAPH {
	edge e[N<<1]; int head[N],cnt;
	GRAPH() {
		cnt=0;
	}
	void add_edge(int x,int y) {
		e[++cnt]=(edge){head[x],y}; head[x]=cnt;
	}
}G,T;

namespace TAR {
	stack<int>ST;
	int low[N],dfn[N],tarjan_tot=0;
	void tarjan(int x) {
		ST.push(x); low[x]=dfn[x]=++tarjan_tot;
		for(int i=G.head[x];i;i=G.e[i].nex) {
			int y=G.e[i].to;
			if(!dfn[y]) {
				tarjan(y),low[x]=min(low[x],low[y]);
				if(low[y]>=dfn[x]) {
					++fang_tot;// S[fang_tot].insert(val[x]); 这里1 
					int qwq; T.add_edge(fang_tot,x); T.add_edge(x,fang_tot);
					do {
						qwq=ST.top(); ST.pop(); //S[fang_tot].insert(val[qwq]); 这里1 
						T.add_edge(fang_tot,qwq); T.add_edge(qwq,fang_tot);	
					} while(qwq!=y);
				}
			}
			else low[x]=min(low[x],dfn[y]);
		}
	}
}

struct BIT {
	#define ls (cur<<1)
	#define rs (ls|1)
	int sum[N<<2];
	BIT() {
		memset(sum,0x3f,sizeof(sum));
	}
	void update(int cur,int l,int r,int pos,int v) {
		if(l==r) return sum[cur]=v,void();
		int mid=(l+r)>>1;
		if(pos<=mid) update(ls,l,mid,pos,v);
		else update(rs,mid+1,r,pos,v);
		sum[cur]=min(sum[ls],sum[rs]); 
	}
	int query(int cur,int l,int r,int cl,int cr) {
		if(cl<=l&&r<=cr) return sum[cur];
		int mid=(l+r)>>1,res=inf;
		if(cl<=mid) res=min(res,query(ls,l,mid,cl,cr));
		if(cr>mid) res=min(res,query(rs,mid+1,r,cl,cr));
		return res;
	}
}TR;

void dfs1(int x,int ff) {
	fa[x]=ff; sz[x]=1; son[x]=0; dep[x]=dep[ff]+1;
	if(x<=n&&ff>n) S[ff].insert(val[x]); //这里2 
	for(int i=T.head[x];i;i=T.e[i].nex) {
		int y=T.e[i].to;
		if(y==ff) continue;
		dfs1(y,x); sz[x]+=sz[y];
		if(sz[y]>sz[son[x]]) son[x]=y;
	}
} 

void dfs2(int x,int tp) {
	top[x]=tp; id[x]=++sp_tot; rk[sp_tot]=x;
	if(son[x]) dfs2(son[x],tp);
	for(int i=T.head[x];i;i=T.e[i].nex) {
		int y=T.e[i].to;
		if(y==son[x]||y==fa[x]) continue;
		dfs2(y,y);
	}
}

void update(int x,int v) {
	if(fa[x]) {
		S[fa[x]].erase(S[fa[x]].find(val[x])); S[fa[x]].insert(v); TR.update(1,1,fang_tot,id[fa[x]],*S[fa[x]].begin());
	}
	val[x]=v; TR.update(1,1,fang_tot,id[x],v);
}

int query(int x,int y) {
	int res=inf;
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		res=min(res,TR.query(1,1,fang_tot,id[top[x]],id[x]));
		x=fa[top[x]];
	}
	if(id[x]>id[y]) swap(x,y);
	res=min(res,TR.query(1,1,fang_tot,id[x],id[y]));
	if(x<=n) return res;
	else return min(res,val[fa[x]]);
}

int main() {
	int x,y; char op; val[0]=inf;
	fang_tot=n=rd(); m=rd(); Q=rd();
	for(int i=1;i<=n;i++) val[i]=rd();
	for(int i=1;i<=m;i++) {
		x=rd(); y=rd();
		G.add_edge(x,y); G.add_edge(y,x);
	}
	TAR::tarjan(1); dfs1(1,0); dfs2(1,0);
	for(int i=1;i<=n;i++) TR.update(1,1,fang_tot,id[i],val[i]);
	for(int i=n+1;i<=fang_tot;i++) TR.update(1,1,fang_tot,id[i],*S[i].begin());
	while(Q--) {
		cin>>op; x=rd(); y=rd();
		if(op=='C') {
			update(x,y);
		} else printf("%d\n",query(x,y));
	}
	return 0;
}
2021/8/10 14:01
加载中...