zoukankan      html  css  js  c++  java
  • [BZOJ5329] [SDOI2018] 战略游戏

    题目链接

    BZOJ.

    LOJ.

    Solution

    对原图建立圆方树。

    那么可以注意到只有圆点会被算到答案,对于一个圆点,合法当且仅当去掉这个点之后的若干个连通块有两个或以上有标记点。

    那么可以对标记点在圆方树上建立虚树,那么虚树边上的圆点和那些作为(LCA)建上去的圆点的个数即为答案。

    注意建虚树时把(1)号点建进去的话要特判(1)号点和所连的边选不选。

    这题是真的难码...

    #include<bits/stdc++.h>
    using namespace std;
    
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
    
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    #define lf double
    #define ll long long 
    
    const int maxn = 5e5+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    
    int n,m,cnt,sz[maxn],dfn[maxn],dis[maxn],dfncnt;
    
    struct Tree {
    	int head[maxn],tot,dep[maxn],fa[maxn][20];
    	struct edge{int to,nxt;}e[maxn<<1];
    
    	void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
    	void ins(int u,int v) {add(u,v),add(v,u);}
    	
    	void dfs(int x,int Fa) {
    		dis[x]=dis[Fa]+(x<=n),dep[x]=dep[Fa]+1,fa[x][0]=Fa,dfn[x]=++dfncnt,sz[x]=1;
    		for(int i=1;i<=18;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    		for(int i=head[x];i;i=e[i].nxt)
    			if(e[i].to!=Fa) dfs(e[i].to,x),sz[x]+=sz[e[i].to];
    	}
    	
    	int lca(int x,int y) {
    		if(dep[x]<dep[y]) swap(x,y);
    		for(int i=18;~i;i--) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
    		if(x==y) return x;
    		for(int i=18;~i;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    		return fa[x][0];
    	}
    	
    	void clear() {
    		for(int i=1;i<=cnt;i++) sz[i]=dfn[i]=dis[i]=head[i]=dep[i]=0;
    		tot=dfncnt=0;
    	}
    }T;
    
    struct Graph {
    	int head[maxn],tot,Dfn[maxn],low[maxn],dfn_cnt,sta[maxn],top,vis[maxn];
    	struct edge{int to,nxt;}e[maxn<<1];
    
    	void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
    	void ins(int u,int v) {add(u,v),add(v,u);}
    	
    	void clear() {
    		for(int i=1;i<=cnt;i++) head[i]=Dfn[i]=low[i]=sta[i]=vis[i]=0;
    		dfn_cnt=tot=top=0;
    	}
    	
    	void tarjan(int x,int fa) {
    		low[x]=Dfn[x]=++dfn_cnt;sta[++top]=x;vis[x]=1;
    		for(int v,i=head[x];i;i=e[i].nxt) {
    			if((v=e[i].to)==fa) continue;
    			if(Dfn[v]) {low[x]=min(low[x],Dfn[v]);continue;}
    			tarjan(v,x);
    			low[x]=min(low[x],low[v]);
    			if(low[v]>=Dfn[x]) {
    				++cnt;
    				while(top) {
    					int now=sta[top--];
    					T.ins(now,cnt);
    					if(now==v) break;
    				}T.ins(cnt,x);
    			}
    		}
    	}
    	
    	void prepare() {
    		for(int i=1,x,y;i<=m;i++) read(x),read(y),ins(x,y);
    		cnt=n,tarjan(1,0),T.dfs(1,0);
    	}
    }G;
    
    int cmp(int x,int y) {return dfn[x]<dfn[y];}
    
    struct Virtual_Tree {
    	int head[maxn],tot,ans,use[maxn],used,sta[maxn],top,in[maxn],k,vis[maxn],op;
    	struct edge{int to,nxt,w;}e[maxn<<1];
    
    	void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
    	void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}
    	
    	void build() {
    		sort(in+1,in+k+1,cmp);sta[++top]=1;
    		for(int i=1;i<=k;i++) {
    			if(in[i]==1) continue;
    			int t=T.lca(sta[top],in[i]),pre=-1;
    			while(dfn[sta[top]]>dfn[t]&&dfn[sta[top]]<dfn[t]+sz[t]) {
    				if(pre!=-1) ins(pre,sta[top],dis[pre]-dis[sta[top]]-(pre<=n));
    				use[++used]=pre=sta[top];top--;
    			}
    			if(pre!=-1) ins(pre,t,dis[pre]-dis[t]-(pre<=n));
    			if(sta[top]!=t) sta[++top]=t;
    			sta[++top]=in[i];
    		}
    		int pre=-1;
    		while(top) {
    			if(pre!=-1) ins(pre,sta[top],dis[pre]-dis[sta[top]]-(pre<=n));
    			use[++used]=pre=sta[top];top--;
    		}
    	}
    	
    	void clear() {
    		for(int i=1;i<=used;i++) head[use[i]]=vis[use[i]]=0;
    		top=used=tot=0;
    	}
    	
    	void dfs(int x,int fa) {
    		if(!vis[x]) ans+=x<=n;
    		for(int i=head[x];i;i=e[i].nxt)
    			if(e[i].to!=fa) dfs(e[i].to,x),ans+=e[i].w;
    	}
    	
    	void solve() {
    		read(k);for(int i=1;i<=k;i++) read(in[i]),vis[in[i]]=1;
    		build();op=0;for(int i=head[1];i;i=e[i].nxt) op++;
    		ans=0;dfs(1,0);
    		if(op==1&&in[1]!=1) {
    			ans--;
    			for(int i=head[1];i;i=e[i].nxt) ans-=e[i].w;
    		}
    		write(ans);clear();
    	}
    }VT;
    
    void solve() {
    	read(n),read(m),G.prepare();
    	int q;read(q);for(int i=1;i<=q;i++) VT.solve();
    }
    
    int main() {
    	int t;read(t);while(t--) solve(),G.clear(),T.clear();
    	return 0;
    }
    
  • 相关阅读:
    DOM
    js中字符串常规操作
    placeholer改变默认灰色
    css重置reset.css
    倒计时跳转
    手机中间四位用*代替
    animation
    过渡
    flex布局
    css3几个新属性
  • 原文地址:https://www.cnblogs.com/hbyer/p/10609137.html
Copyright © 2011-2022 走看看