zoukankan      html  css  js  c++  java
  • CF487E Tourists

    题目链接
    还是圆方树.
    考虑如果可以走到一个连通分量,一定可以走到这个连通分量的最小值.
    那么维护搜索栈,找点双.
    这一部分自行学习.
    假设已经建出了圆方树,然后(dfs)一遍.
    圆点直接维护权值,方点用一个(multiset)维护它的所有儿子的权值.
    然后树剖+线段树维护区间最小值即可.
    注意询问的时候如果(LCA)是方点还要算上它父亲的贡献.
    哦这道题不是仙人掌.
    所以不能直接拉环.
    我不会告诉你因为这个我爆了10发CF
    代码如下

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #include<set>
    #define N (400010)
    #define M (600010)
    #define inf (0x7f7f7f7f)
    #define rg register int
    #define Label puts("NAIVE")
    #define spa print(' ')
    #define ent print('
    ')
    #define rand() (((rand())<<(15))^(rand()))
    typedef long double ld;
    typedef long long LL;
    typedef unsigned long long ull;
    using namespace std;
    inline char read(){
    	static const int IN_LEN=1000000;
    	static char buf[IN_LEN],*s,*t;
    	return (s==t?t=(s=buf)+fread(buf,1,IN_LEN,stdin),(s==t?-1:*s++):*s++);
    }
    template<class T>
    inline void read(T &x){
    	static bool iosig;
    	static char c;
    	for(iosig=false,c=read();!isdigit(c);c=read()){
    		if(c=='-')iosig=true;
    		if(c==-1)return;
    	}
    	for(x=0;isdigit(c);c=read())x=((x+(x<<2))<<1)+(c^'0');
    	if(iosig)x=-x;
    }
    inline char readchar(){
    	static char c;
    	for(c=read();!isalpha(c);c=read())
    	if(c==-1)return 0;
    	return c;
    }
    const int OUT_LEN = 10000000;
    char obuf[OUT_LEN],*ooh=obuf;
    inline void print(char c) {
    	if(ooh==obuf+OUT_LEN)fwrite(obuf,1,OUT_LEN,stdout),ooh=obuf;
    	*ooh++=c;
    }
    template<class T>
    inline void print(T x){
    	static int buf[30],cnt;
    	if(x==0)print('0');
    	else{
    		if(x<0)print('-'),x=-x;
    		for(cnt=0;x;x/=10)buf[++cnt]=x%10+48;
    		while(cnt)print((char)buf[cnt--]);
    	}
    }
    inline void flush(){fwrite(obuf,1,ooh-obuf,stdout);}
    struct xds{
    	int l,r,mi;
    }a[N<<3];
    int F[N],Ne[M<<1],B[M<<1];
    multiset<int> S[N];
    multiset<int>::iterator it;
    bool ins[N];
    int n,m,w[N],fi[N],ne[M<<1],b[M<<1],fa[N],top[N],siz[N],son[N];
    int dfn[N],low[N],ind,rdfn[N],cnt,E,dep[N],Q,E2,st[N],tp;
    void add(int x,int y){
    	ne[++E]=fi[x],fi[x]=E,b[E]=y;
    	ne[++E]=fi[y],fi[y]=E,b[E]=x;
    }
    void add2(int x,int y){
    	Ne[++E2]=F[x],F[x]=E2,B[E2]=y;
    }
    void dfs1(int u,int pre){
    	fa[u]=pre,siz[u]=1;
    	for(int i=fi[u];i;i=ne[i]){
    		int v=b[i];
    		if(v==pre)continue;
    		dep[v]=dep[u]+1,dfs1(v,u),siz[u]+=siz[v];
    		if(siz[v]>siz[son[u]])son[u]=v; 
    	}
    	if(u>n){
    		for(int i=fi[u];i;i=ne[i])
    		if(b[i]!=pre)S[u].insert(w[b[i]]);
    	}
    }
    void dfs2(int u){
    	dfn[u]=++ind,rdfn[ind]=u;
    	if(son[u])top[son[u]]=top[u],dfs2(son[u]);
    	for(int i=fi[u];i;i=ne[i]){
    		int v=b[i];
    		if(v!=fa[u]&&v!=son[u])
    		top[v]=v,dfs2(v);
    	}
    }
    void tarjan(int u,int pre){
    	dfn[u]=low[u]=++ind;
    	fa[u]=pre,st[++tp]=u;
    	for(int i=F[u];i;i=Ne[i]){
    		int v=B[i];
    		if(!dfn[v]){
    			tarjan(v,u),low[u]=min(low[u],low[v]);
    			if(low[v]>=dfn[u]){
    				add(++cnt,u);
    				while(st[tp+1]!=v)add(st[tp],cnt),tp--;
    			}
    		}
    		low[u]=min(low[u],dfn[v]);
    	}
    }
    void build(int l,int r,int x){
    	a[x].l=l,a[x].r=r;
    	if(l==r){
    		int u=rdfn[l];
    		if(u<=n)a[x].mi=w[u];
    		else a[x].mi=*S[u].begin();
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(l,mid,x*2),build(mid+1,r,x*2+1);
    	a[x].mi=min(a[x*2].mi,a[x*2+1].mi);
    }
    void change(int k,int v,int x){
    	if(a[x].l==a[x].r){
    		a[x].mi=v;
    		return;
    	}
    	int mid=(a[x].l+a[x].r)>>1;
    	if(k<=mid)change(k,v,x*2);
    	else change(k,v,x*2+1);
    	a[x].mi=min(a[x*2].mi,a[x*2+1].mi);
    }
    void modify(int x,int val){
    	int ff=fa[x],pmin;
    	change(dfn[x],val,1);
    	if(ff>n){
    		pmin=*S[ff].begin();
    		it=S[ff].find(w[x]);
    		if(it!=S[ff].end())S[ff].erase(it);
    		S[ff].insert(val);
    		int nmin=*S[ff].begin();
    		if(nmin!=pmin)change(dfn[ff],nmin,1);
    	}
    	w[x]=val;
    }
    int query(int l,int r,int x){
    	if(a[x].l==l&&a[x].r==r)return a[x].mi;
    	int mid=(a[x].l+a[x].r)>>1;
    	if(r<=mid)return query(l,r,x*2);
    	else if(l>mid)return query(l,r,x*2+1);
    	else return min(query(l,mid,x*2),query(mid+1,r,x*2+1));
    }
    int query(int u,int v){
    	int ans=inf;
    	while(top[u]!=top[v]){
    		if(dep[top[u]]<dep[top[v]])swap(u,v);
    		ans=min(ans,query(dfn[top[u]],dfn[u],1));
    		u=fa[top[u]];
    	}
    	if(dep[u]>dep[v])swap(u,v);
    	ans=min(ans,query(dfn[u],dfn[v],1));
    	if(u>n)ans=min(ans,w[fa[u]]);
    	return ans;
    }
    int main(){
    	read(n),read(m),read(Q),cnt=n;
    	for(int i=1;i<=n;i++)read(w[i]);
    	for(int i=1,x,y;i<=m;i++){
    		read(x),read(y);
    		add2(x,y),add2(y,x);
    	}
    	tarjan(1,0),ind=0,dfs1(1,0),top[1]=1,dfs2(1),fa[1]=1;
    	build(1,cnt,1);
    	while(Q--){
    		char ch=readchar();
    		int x,y; read(x),read(y);
    		if(ch=='A')print(query(x,y)),ent;
    		else modify(x,y);
    	}
    	return flush(),0;
    }
    
  • 相关阅读:
    linux学习之路7 linux下获取帮助
    51nod 1002 数塔取数问题
    51nod 1002 数塔取数问题
    51nod 1001 数组中和等于K的数对
    51nod 1001 数组中和等于K的数对
    linux学习之路6 Vi文本编辑器
    linux学习之路6 Vi文本编辑器
    计算误差——ACM计算几何中的精度问题
    计算误差——ACM计算几何中的精度问题
    daily_journal_3 the game of thrones
  • 原文地址:https://www.cnblogs.com/Romeolong/p/10057413.html
Copyright © 2011-2022 走看看