【UOJ】#30. 【CF Round #278】Tourists-广义圆方树&set&树剖

传送门:uoj30


题解

圆方树建出来:每个方点 x x x用multiset维护它的所有儿子圆点的 w i w_i wi w x w_x wx就是multiset中的最小值。

每次修改至多影响两个点(该点和它的父结点),树剖维护即可。


代码

#include<bits/stdc++.h>
#define gc getchar
#define mid (l+r>>1)
#define lc k<<1
#define rc k<<1|1 
using namespace std;
const int N=2e5+10;
typedef long long ll;

int n,m,q,num,tg[N],w[N],mn[N<<2];
int df[N],low[N],stk[N],top,dfn;
int sz[N],son[N],dep[N],tpo[N],f[N],rv[N],cnt;
ll ans;

multiset<int>st[N];

char cp;
template<class T>inline void rd(T &x)
{
	cp=gc();x=0;int f=0;
	for(;!isdigit(cp);cp=gc()) if(cp=='-') f=1;
	for(;isdigit(cp);cp=gc()) x=x*10+(cp^48);
	if(f) x=-x;
}

inline int ask_typ()
{
	for(;;){
		cp=gc();
		if(cp=='C') return 0;
		if(cp=='A') return 1;
	}
}

struct gra{
int head[N],to[N<<1],nxt[N<<1],tot;
inline void lk(int u,int v)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;}
}A,B;

void tar(int x)
{
	int i,j,tp;df[x]=low[x]=++dfn;stk[++top]=x;
	for(i=A.head[x];i;i=A.nxt[i]){
	    j=A.to[i];
		if(!df[j]){
		  	tar(j);
			if(low[j]>=df[x]){
				B.lk(x,++num);
			   	for(;;){
			   	    tp=stk[top--];B.lk(num,tp);
			   	    st[num].insert(w[tp]);
				    if(tp==j) break;	
				}
			}else low[x]=min(low[x],low[j]); 
		}else low[x]=min(low[x],df[j]);
    }
}

void dfs1(int x)
{
	int j,i;sz[x]=1;
	if(x>n) w[x]=*(st[x].begin());
	for(i=B.head[x];i;i=B.nxt[i]){
		j=B.to[i];if(j==f[x]) continue;
		f[j]=x;dep[j]=dep[x]+1;dfs1(j);sz[x]+=sz[j];
		if((!son[x])||(sz[son[x]]<sz[j])) son[x]=j;
	}
}

void dfs2(int x,int tpp)
{
	int i,j;tpo[x]=tpp;tg[x]=++cnt;rv[cnt]=x;
	if(!son[x]) return;dfs2(son[x],tpp); 
	for(i=B.head[x];i;i=B.nxt[i]){
		j=B.to[i];if(j==f[x] || j==son[x]) continue;
		dfs2(j,j);
	}
}

inline void pu(int k){mn[k]=min(mn[lc],mn[rc]);}

void build(int k,int l,int r)
{
	if(l==r) {mn[k]=w[rv[l]];return;}
	build(lc,l,mid);build(rc,mid+1,r);
	pu(k);
}

int qr(int k,int l,int r,int L,int R)
{
	if(L<=l && r<=R) return mn[k];
	if(R<=mid) return qr(lc,l,mid,L,R);
	if(L>mid) return qr(rc,mid+1,r,L,R);
	return min(qr(lc,l,mid,L,R),qr(rc,mid+1,r,L,R));
}

void trs(int k,int l,int r,int pos)
{
	if(l==r) {mn[k]=w[rv[l]];return;}
	if(pos<=mid) trs(lc,l,mid,pos);
	else trs(rc,mid+1,r,pos);
	pu(k);
}

inline int ask(int x,int y)
{
	int re=2e9;
	for(;tpo[x]!=tpo[y];x=f[tpo[x]]){
		if(dep[tpo[x]]<dep[tpo[y]]) swap(x,y);
		re=min(re,qr(1,1,num,tg[tpo[x]],tg[x]));
	}
	if(dep[x]<dep[y]) swap(x,y);
	re=min(re,qr(1,1,num,tg[y],tg[x]));
	if(y>n) re=min(re,w[f[y]]);
	return re;
}

inline void chg(int x,int vl)
{
	int y=f[x];
	if(y){
		st[y].erase(st[y].find(w[x]));
		st[y].insert(vl);
		w[y]=*(st[y].begin());
		trs(1,1,num,tg[y]);
	}
    w[x]=vl;trs(1,1,num,tg[x]);
} 

int main(){
	int i,j,x,y;
    rd(n);rd(m);rd(q);num=n;
    for(i=1;i<=n;++i) rd(w[i]);
    for(i=1;i<=m;++i){
    	rd(x);rd(y);
		A.lk(x,y);A.lk(y,x);
	}
	tar(1);dep[1]=1;dfs1(1);dfs2(1,1);
	build(1,1,num);
	for(;q;--q){
		if(ask_typ()){
           rd(x);rd(y);printf("%d\n",ask(x,y));		
		}else{
		   rd(x);rd(y);chg(x,y);
		} 
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值