ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[SDOI2018]战略游戏

2021-04-06 14:04:49  阅读:199  来源: 互联网

标签:游戏 int 200100 tp stk -- low SDOI2018 战略


III.[SDOI2018]战略游戏

这题我居然能1A,神奇,神奇

本题是老缝合怪了,强行把一个圆方树板子跟一个虚树板子缝到了一起。不会虚树的可以参见笔者的虚树学习笔记

具体来说,首先我们先建出圆方树出来;然后,再在圆方树上针对给定的点集跑出虚树出来;然后,对圆方树上的圆点数量做一个树上前缀和(本题只能删圆点,不能删方点),在虚树上每一条边用儿子的前缀和减去父亲的前缀和即可。注意到如果虚树中的虚点(即LCA节点)是圆点的话,则它也是可以被删去的,应该被计入答案。

代码(namespacenamespace真有意思):

#include<bits/stdc++.h>
using namespace std;
int T,n,m,q,c;
namespace Tree{
	int dep[200100],sum[200100],anc[200100][20],dfn[200100],tot;
	namespace real{
		vector<int>v[200100];
		void ae(int x,int y){v[x].push_back(y),v[y].push_back(x);}
		void dfs(int x,int fa){
			sum[x]=sum[fa]+(x<=n),anc[x][0]=fa,dep[x]=dep[fa]+1,dfn[x]=++tot;
			for(int i=1;i<=19;i++)anc[x][i]=anc[anc[x][i-1]][i-1];
			for(auto y:v[x])if(y!=fa)dfs(y,x);
		}
	}
	int LCA(int x,int y){
		if(dep[x]>dep[y])swap(x,y);
		for(int i=19;i>=0;i--)if(dep[x]<=dep[y]-(1<<i))y=anc[y][i];
		if(x==y)return x;
		for(int i=19;i>=0;i--)if(anc[x][i]!=anc[y][i])x=anc[x][i],y=anc[y][i];
		return anc[x][0];
	}
	namespace imag{
		int a[100100],stk[200100],tp,sz[200100],all,res;
		bool marked[200100];
		vector<int>v[200100];
		bool cmp(int x,int y){return dfn[x]<dfn[y];}
		void ae(int x,int y){v[x].push_back(y);}
		void ins(int x){
			marked[x]=true,sz[x]=1;
			if(!tp){stk[++tp]=x;return;}
			int lca=LCA(x,stk[tp]);
			while(tp>=2&&dep[stk[tp-1]]>dep[lca])ae(stk[tp-1],stk[tp]),tp--;
			if(tp&&dep[stk[tp]]>dep[lca])ae(lca,stk[tp--]);
			if(!tp||stk[tp]!=lca)stk[++tp]=lca;
			stk[++tp]=x;
		}
		void fin(){
			while(tp>=2)ae(stk[tp-1],stk[tp]),tp--;
			tp--;
		}
		void dfs1(int x){
			int msz=0;
			for(auto y:v[x]){
				dfs1(y);
				if(sz[y]<all)res+=sum[anc[y][0]]-sum[x];
				sz[x]+=sz[y],msz=max(msz,sz[y]);
			}
			if(!marked[x]&&msz<sz[x]&&x<=n)res++;
		}
		void dfs2(int x){
			sz[x]=marked[x]=0;
			for(auto y:v[x])dfs2(y);
			v[x].clear();
		}
		int work(){
			scanf("%d",&all),res=0;
			for(int i=1;i<=all;i++)scanf("%d",&a[i]);
			sort(a+1,a+all+1,cmp);
			if(a[1]!=1)stk[tp=1]=1;
			for(int i=1;i<=all;i++)ins(a[i]);
			fin();
			dfs1(1),dfs2(1);
			return res;
		}		
	}
}
namespace Graph{
	vector<int>v[100100];
	int dfn[100100],low[100100],tot;
	stack<int>s;
	void Tarjan(int x){
		dfn[x]=low[x]=++tot,s.push(x);
		for(auto y:v[x]){
			if(!dfn[y]){
				Tarjan(y),low[x]=min(low[x],low[y]);
				if(low[y]>=dfn[x]){
					Tree::real::v[++c].clear();
					while(s.top()!=y)Tree::real::ae(c,s.top()),s.pop();
					Tree::real::ae(c,s.top()),s.pop();
					Tree::real::ae(c,x);
				}
			}else low[x]=min(low[x],dfn[y]);
		}
	}
}
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m),c=n,Graph::tot=Tree::tot=0;
		for(int i=1;i<=n;i++)Graph::v[i].clear(),Tree::real::v[i].clear(),Graph::dfn[i]=Graph::low[i]=0;
		for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),Graph::v[x].push_back(y),Graph::v[y].push_back(x);
		Graph::Tarjan(1),Graph::s.pop();
		Tree::real::dfs(1,0);
		scanf("%d",&q);
		while(q--)printf("%d\n",Tree::imag::work());
	}
	return 0;
} 

标签:游戏,int,200100,tp,stk,--,low,SDOI2018,战略
来源: https://www.cnblogs.com/Troverld/p/14621513.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有