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

    LINK:战略游戏

    一道很有价值的题目。这道题 一张无向联通图 每次询问给出K个关键点 问摧毁图中哪个点可以使得这K个关键的两两之间有一对不能联通 去掉的这个点不能是关键点 求方案数。

    可以发现 当K==2的时候 我们从一个点到另外一个点 能摧毁的必然是关键点 一张无向联通图 如果是关键点的话 那么必然不存在另外一条路径 所以这个关键点符合割点的定义 我们只需要求出路径上有多少个割点即可。

    考虑 K个点怎么做 可以发现建出圆方树 这样两点之间的割点数量就是圆方树上圆点数量。那么我们只要建出虚树按边来统计答案即可。

    更简便的是我们K个点按dfs序排序后 两两之间的路径形成了整体的两倍。不需要建虚树直接计算即可。

    考虑这是点权 并非边权 所以我们把点权放到边权上 显然是放到父亲的那个边上。这样统计下来可以发现只有最上方的公共LCA没有被统计到 加上即可。

    最上方LCA 显然是深度最浅的所以我们可以比大小得出 更简便的是 考虑dfs序 可以发现 LCA为第一个点和最后一个点的LCA。

    坑点:多组数据 清空一定要清空好 多测不清空 爆零两行泪。我就是以为自己清空了 结果没清空干净导致GG 调了2h硬是没看出来哪错了。

    我的倍增数组f 没有清空我以为不用清空其实是需要的 在倍增的时候可能有上次的信息 导致找不到LCA 这点值得特殊注意。

    const int MAXN=200010;
    int T,n,Q,m,len,cnt,id,top,sum;
    int dfn[MAXN],f[MAXN][20],Log[MAXN],low[MAXN],d[MAXN],s[MAXN];
    int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1],v[MAXN],a[MAXN];
    vector<int>g[MAXN];
    inline void cle()
    {
    	id=top=len=cnt=0;
    	rep(1,200000,i)lin[i]=0,g[i].clear(),dfn[i]=0,v[i]=0,low[i]=0;
    }
    inline int cmp(int a,int b){return dfn[a]<=dfn[b];}
    inline void add(int x,int y)
    {
    	ver[++len]=y;
    	nex[len]=lin[x];
    	lin[x]=len;
    }
    inline void dfs(int x)//构建圆方树
    {
    	dfn[x]=low[x]=++cnt;
    	s[++top]=x;
    	for(int i=lin[x];i;i=nex[i])
    	{
    		int tn=ver[i];
    		if(!dfn[tn])
    		{
    			dfs(tn);
    			low[x]=min(low[x],low[tn]);
    			if(dfn[x]==low[tn])//x为近似割点
    			{
    				++id;
    				for(int j=0;j!=tn;--top)
    				{
    					j=s[top];
    					g[id].pb(j);
    				}
    				g[x].pb(id);
    			}
    		}
    		else low[x]=min(low[x],dfn[tn]);
    	}
    }
    inline int LCA(int x,int y)
    {
    	if(d[x]<d[y])swap(x,y);
    	for(int i=Log[d[x]];i>=0;--i)
    		if(d[f[x][i]]>=d[y])x=f[x][i];
    	if(x==y)return x;
    	for(int i=Log[d[x]];i>=0;--i)
    		if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    inline void dp(int x,int fa)
    {
    	d[x]=d[fa]+1;dfn[x]=++cnt;
    	//if(T==0){++sum;cout<<d[x]<<' '<<sum<<endl;}
    	v[x]=v[fa]+(x<=n);f[x][0]=fa;
    	rep(1,19,i)f[x][i]=f[f[x][i-1]][i-1];
    	if(!g[x].size())return;
    	rep(0,g[x].size()-1,i)
    	{
    		int tn=g[x][i];
    		dp(tn,x);
    	}
    }
    int main()
    {
    	freopen("1.in","r",stdin);
    	get(T);
    	rep(2,200000,i)Log[i]=Log[i>>1]+1;
    	while(T--)
    	{
    		get(n);get(m);
    		cle();id=n;
    		rep(1,m,i)
    		{
    			int x,y;
    			get(x);get(y);
    			add(x,y);add(y,x);
    		}
    		dfs(1);
    		cnt=0;//put(id);
    		dp(1,0);
    		get(Q);
    		//rep(1,id,i)put(v[i]);
    		//if(top!=1){puts("ww");return 0;}
    		rep(1,Q,i)
    		{
    			int x;get(x);
    			rep(1,x,j)get(a[j]);
    			sort(a+1,a+1+x,cmp);
    			int ans=0;a[x+1]=a[1];
    			int minn=INF,p=0;
    			rep(1,x,j)
    			{
    				int lca=LCA(a[j],a[j+1]);
    				if(d[lca]<minn)minn=d[lca],p=lca;
    				ans+=v[a[j]]+v[a[j+1]]-v[lca]*2;
    			}
    			//put(ans);
    			ans+=(p<=n)*2;
    			ans=ans>>1;ans-=x;
    			put(ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    圣杯局部和双飞翼布局
    解决css英文换行问题
    存在即合理--字体样式大全
    存在即合理---个别软件下载
    sublime Text3常见插件汇总
    省略的方法
    JS数组方法与python列表方法的比较
    vue中数据改变,强制视图更新,视图不更新的原因和解决办法
    Vue通信
    路由的缓存
  • 原文地址:https://www.cnblogs.com/chdy/p/12530958.html
Copyright © 2011-2022 走看看