zoukankan      html  css  js  c++  java
  • 【CF613D】Kingdom and its Cities 虚树+树形DP

    【CF613D】Kingdom and its Cities

    题意:给你一棵树,每次询问给出k个关键点,问做多干掉多少个非关键点才能使得所有关键点两两不连通。

    $n,sum kle 10^5$

    题解:刷虚树板子啦!

    首先如果两个关键点相邻则无解。然后建出虚树,进行树形DP。设f[i]表示i子树中的关键点都不连通,且i子树中的点与外面的点也不连通的最小花费,g[i]表示i子树重的关键点都不连通,且子树中只有一个点与外面的点连通的最小花费。转移时讨论一波即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    using namespace std;
    const int maxn=100010;
    int n,m,now,cnt,top;
    int to[maxn<<1],nxt[maxn<<1],head[maxn],fa[19][maxn],Log[maxn],dep[maxn],A[maxn],vis[maxn],st[maxn],f[maxn],g[maxn],p[maxn],q[maxn];
    vector<int> ch[maxn];
    void dfs(int x)
    {
    	p[x]=++q[0],q[q[0]]=x;
    	for(int i=head[x];i!=-1;i=nxt[i])	if(to[i]!=fa[0][x])	fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,dfs(to[i]);
    }
    inline void add(int a,int b)
    {
    	to[cnt]=b,nxt[cnt]=head[a],head[a]=cnt++;
    }
    bool cmp(const int &a,const int &b)
    {
    	return p[a]<p[b];
    }
    inline int lca(int a,int b)
    {
    	if(dep[a]<dep[b])	swap(a,b);
    	for(int i=Log[dep[a]-dep[b]];i>=0;i--)	if(dep[fa[i][a]]>=dep[b])	a=fa[i][a];
    	if(a==b)	return a;
    	for(int i=Log[dep[a]];i>=0;i--)	if(fa[i][a]!=fa[i][b])	a=fa[i][a],b=fa[i][b];
    	return fa[0][a];
    }
    void DP(int x)
    {
    	int y,t0=0,t1=0,t2=0;
    	vector<int>::iterator it;
    	for(it=ch[x].begin();it!=ch[x].end();it++)
    	{
    		y=*it,DP(y);
    		t2=min(t2+f[y],t0+min(f[y],g[y])),t0+=f[y],t1+=min(f[y],g[y]);
    	}
    	ch[x].clear();
    	if(vis[x]==now)
    	{
    		g[x]=t0,f[x]=t0+1;
    	}
    	else
    	{
    		g[x]=t2,f[x]=min(t1+1,t0);
    	}
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	//freopen("a.in","r",stdin);
    	n=rd();
    	int i,j,a,b,c;
    	memset(head,-1,sizeof(head));
    	for(i=2;i<=n;i++)	a=rd(),b=rd(),add(a,b),add(b,a),Log[i]=Log[i>>1]+1;
    	dep[1]=1,dfs(1);
    	for(j=1;(1<<j)<=n;j++)	for(i=1;i<=n;i++)	fa[j][i]=fa[j-1][fa[j-1][i]];
    	m=rd();
    	for(now=1;now<=m;now++)
    	{
    		a=rd();
    		for(i=1;i<=a;i++)	A[i]=rd(),vis[A[i]]=now;
    		for(i=1;i<=a;i++)	if(vis[fa[0][A[i]]]==now)
    		{
    			puts("-1");
    			break;
    		}
    		if(i<=a)	continue;
    		sort(A+1,A+a+1,cmp);
    		st[top=1]=A[1];
    		for(i=2;i<=a;i++)
    		{
    			c=lca(A[i-1],A[i]);
    			while(top&&dep[st[top]]>dep[c])
    			{
    				b=st[top--];
    				if(top&&dep[st[top]]>dep[c])	ch[st[top]].push_back(b);
    				else	ch[c].push_back(b);
    			}
    			if(!top||st[top]!=c)	st[++top]=c;
    			st[++top]=A[i];
    		}
    		while(top>1)	ch[st[top-1]].push_back(st[top]),top--;
    		DP(st[top]);
    		a=min(g[st[top]],f[st[top]]);
    		printf("%d
    ",a);
    	}
    	return 0;
    }
  • 相关阅读:
    Scrapy 概览笔记
    Python 依赖版本控制 (requirements.txt 文件生成和使用)
    Python 虚拟空间的使用
    macOS 所有版本 JDK 安装指南 (with Homebrew)
    鉴权那些事
    Java 位运算符和 int 类型的实现
    ASP.NET Core 入门教程 5、ASP.NET Core MVC 视图传值入门
    如何做好一次知识或技术分享
    ASP.NET Core 入门教程 4、ASP.NET Core MVC控制器入门
    ASP.NET Core 入门教程 3、ASP.NET Core MVC路由入门
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/8723947.html
Copyright © 2011-2022 走看看