CF487E Tourists

圆方树的问题。
调了挺久的。
先把圆方树给建出来,然后考虑怎么求答案。
那么一个方点代表一个点双,那自然是这个点双里的答案。
考虑改变一个点时,把这个的点的父亲方点的平衡树里更改。
这样保证复杂度。
于是乎套上树剖,注意当两点\(lca\)为方点时,答案还要考虑该方点的父亲圆点。
开始码,妥妥的码农题(也可能是我菜,码了\(200h\)

CF487E Tourists
#include<iostream>
#include<cstdio>
#include<set>
#include<cstring>
#include<stack>
#define ll long long
#define N 200005

struct P{
	int to,next;
};

struct Map{
	P e[N];
	int cnt,head[N];
	Map(){
		cnt = 0;
		std::memset(head,0,sizeof(head));
	}
	inline void add(int x,int y){
//		std::cout<<x<<" "<<y<<std::endl;
		e[++cnt].to = y;
		e[cnt].next = head[x];
		head[x] = cnt;
	}
}A,T;

int n,m,Q,w[N];

int dfncnt,dfn[N],low[N],fcnt;	
bool vis[N];

std::stack<int>QWQ;

inline void tarjan(int u){
	dfn[u] = low[u] = ++dfncnt;
	QWQ.push(u);
	for(int i = A.head[u];i;i = A.e[i].next){
		int v = A.e[i].to;
		if(!dfn[v]){
			tarjan(v);
			low[u] = std::min(low[u],low[v]);
			if(low[v] == dfn[u]){
				++fcnt;
				while(QWQ.top() != v){
					T.add(fcnt,QWQ.top());
					T.add(QWQ.top(),fcnt);
					QWQ.pop();
				}
				T.add(fcnt,QWQ.top());
				T.add(QWQ.top(),fcnt);
				QWQ.pop();
				T.add(fcnt,u);
				T.add(u,fcnt);				
			}
		}
		else
		low[u] = std::min(low[u],dfn[v]);
	}
}

int dep[N],siz[N],son[N],top[N],to[N],f[N];

inline void dfs(int u,int fa){
	f[u] = fa,siz[u] = 0,dep[u] = dep[fa] + 1;
	for(int i = T.head[u];i;i = T.e[i].next){
		int v = T.e[i].to;
		if(v == fa)
		continue;
		dfs(v,u);
		siz[u] += siz[v];
		if(siz[v] > siz[son[u]])
		son[u] = v;
	}
}

inline void dfs2(int u,int f,int tp){
	dfn[u] = ++dfncnt,to[dfn[u]] = u,top[u] = tp;
	if(son[u])
	dfs2(son[u],u,tp);
	for(int i = T.head[u];i;i = T.e[i].next){
		int v = T.e[i].to;
		if(v == son[u] || v == f)
		continue;
		dfs2(v,u,v);
	}
}

ll t[N << 2];

#define mid ((l + r) >> 1)
#define li (now << 1)
#define ri ((now << 1) | 1)

inline void build(int now,int l,int r){
	if(l == r){
		t[now] = w[to[l]];
//		std::cout<<now<<" "<<l<<" "<<r<<" "<<t[now]<<std::endl;		
		return;
	}
	build(li,l,mid);
	build(ri,mid + 1,r);
	t[now] = std::min(t[li],t[ri]);
//	std::cout<<now<<" "<<l<<" "<<r<<" "<<t[now]<<std::endl;
}

inline void mdf(int now,int l,int r,int p,int x){
	if(l == r){
		t[now] = x;
		return;
	}
	if(p <= mid)
	mdf(li,l,mid,p,x);
	else
	mdf(ri,mid + 1,r,p,x);
	t[now] = std::min(t[li],t[ri]);
}

inline ll q(int now,int l,int r,int tl,int tr){
//	std::cout<<now<<" "<<l<<" "<<r<<" "<<tl<<" "<<tr<<" "<<t[now]<<std::endl;
	if(tl <= l && r <= tr)
	return t[now];
	ll ans = 0x3f3f3f3f;
	if(tl <= mid)
	ans = std::min(ans,q(li,l,mid,tl,tr));
	if(tr > mid)
	ans = std::min(ans,q(ri,mid + 1,r,tl,tr));
	return ans;
}

std::multiset<int> s[N * 2];

int main(){
	scanf("%d%d%d",&n,&m,&Q);
	fcnt = n;
	for(int i = 1;i <= n;++i)
	scanf("%d",&w[i]);
	for(int i = 1;i <= m;++i){
		int x,y;
		scanf("%d%d",&x,&y);
		A.add(x,y);
		A.add(y,x);
	}
	for(int i = 1;i <= n;++i){
		if(!dfn[i])
		tarjan(i);
	}
	dfncnt = 0;
	dfs(1,0);
	dfs2(1,0,1);
	for(int i = 1;i <= n;++i)
	if(f[i])
	s[f[i]].insert(w[i]);
	for(int i = n + 1;i <= dfncnt;++i)
	w[i] = *s[i].begin();
	build(1,1,dfncnt);
	while(Q -- ){
		char a[3];
		int x,y;
		scanf("%s%d%d",a,&x,&y);
		if(a[0] == 'C'){
			if(f[x]){
				s[f[x]].insert(y);
				s[f[x]].erase(s[f[x]].lower_bound(w[x]));
				if(w[f[x]] != *s[f[x]].begin()){
					w[f[x]] = *s[f[x]].begin();
					mdf(1,1,dfncnt,dfn[f[x]],w[f[x]]);
				}
			}
			mdf(1,1,dfncnt,dfn[x],y);
			w[x] = y;
		}
		if(a[0] == 'A'){
			ll ans = 0x3f3f3f3f;
			while(top[x] != top[y]){
				if(dep[top[x]] < dep[top[y]])
				std::swap(x,y);
				ans = std::min(ans,q(1,1,dfncnt,dfn[top[x]],dfn[x]));
				x = f[top[x]];
			}
//			std::cout<<ans<<std::endl;
			if(dfn[x] > dfn[y])
			std::swap(x,y);
			ans = std::min(ans,q(1,1,dfncnt,dfn[x],dfn[y]));
//			std::cout<<ans<<std::endl;
			if(x > n)
			ans = std::min(ans,(ll)w[f[x]]);
			std::cout<<ans<<std::endl;
		}
	}
}
TLE on tese 29 不过实在是不想调了
posted @ 2021-05-04 21:36  fhq_treap  阅读(36)  评论(0编辑  收藏  举报