zoukankan      html  css  js  c++  java
  • 虚树+Kingdom and its Cities

    (Firstly),(DP)的好助手

    适用前提

    有些问题 (n)过大

    导致(m)次询问 (n*m)太大

    且每次DP的关键点是确定的

    这时我们需要虚树

    每一次树上(DP)

    我们都构建虚树然后在树上(DP)

    自然虚树上只包含 关键点 和关键点的(LCA)

    直接枚举(LCA) 时间复杂度是不降反升的

    (Secondly),实现

    所以 如何保证复杂度 构建出虚树 就是虚树的核心了

    大概方法是

    将关键点按前序排序

    然后最开始用栈维护一条链

    若 此时的 (u)与栈顶元素的(LCA)不在链内

    (u)与栈顶元素是(LCA)的两个不同子树的节点

    (只要这句话懂了 就写得出虚树了)

    明显 后期栈维护的不再只是一条链

    这里用数组模拟栈

    具体操作 看代码

    inline void BuildTree(int m)
    {
    	top = 1,st[1] = 1,G[1].clear();
    	for(reg i = 1;i <= m;i++)
    	{
    		if(poi[i] == 1) continue;
    		int lc = lca(poi[i],st[top]);
    		if(lc != st[top])
    		{
    			while(dfn[st[top - 1]] > dfn[lc]) add(st[top - 1],st[top]),top--;
    			if(lc != st[top - 1]) G[lc].clear(),add(lc,st[top]),st[top] = lc;
    			else add(lc,st[top--]);
    		}
    		G[poi[i]].clear(),st[++top] = poi[i];
    	}
    	for(reg i = 1;i < top;i++) add(st[i],st[i + 1]);
    }
    

    (Finally),例题

    Kingdom and its Cities

    #include <map>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define reg register int
    #define isdigit(x) ('0' <= (x)&&(x) <= '9')
    template<typename T>
    inline T Read(T Type)
    {
    	T x = 0,f = 1;
    	char a = getchar();
    	while(!isdigit(a)) {if(a == '-') f = -1;a = getchar();}
    	while(isdigit(a)) {x = (x << 1) + (x << 3) + (a ^ '0');a = getchar();}
    	return x * f;
    }
    const int MAXN = 100010;
    vector<int> G[MAXN];
    int dp[MAXN],size[MAXN];
    int dfn[MAXN],dep[MAXN],fa[MAXN][20],poi[MAXN],st[MAXN],top,cnt;
    bool vis[MAXN];
    inline void add(int u,int v) {G[u].push_back(v);G[v].push_back(u);}
    inline void dfs(int x,int f)
    {
    	dfn[x] = ++cnt;
    	for(reg i = 0;i < G[x].size();i++)
    	{
    		int v = G[x][i];
    		if(v == f) continue;
    		dep[v] = dep[x] + 1,fa[v][0] = x;
    		dfs(v,x);
    	}
    }
    inline void adjust(int &u,int val)
    {
    	for(reg i = 18;i >= 0;i--)
    		if(dep[fa[u][i]] >= val)
    			u = fa[u][i];
    }
    inline int lca(int u,int v)
    {
    	if(dep[u] > dep[v]) adjust(u,dep[v]);
    	if(dep[v] > dep[u]) adjust(v,dep[u]);
    	if(u == v) return v;
    	for(reg i = 18;i >= 0;i--)
    		if(fa[u][i] != fa[v][i])
    			u = fa[u][i],v = fa[v][i];
    	return fa[u][0];
    }
    bool cmp(int a,int b) {return dfn[a] < dfn[b];}
    inline void BuildTree(int m)
    {
    	top = 1,st[1] = 1,G[1].clear();
    	for(reg i = 1;i <= m;i++)
    	{
    		if(poi[i] == 1) continue;
    		int lc = lca(poi[i],st[top]);
    		if(lc != st[top])
    		{
    			while(dfn[st[top - 1]] > dfn[lc]) add(st[top - 1],st[top]),top--;
    			if(lc != st[top - 1]) G[lc].clear(),add(lc,st[top]),st[top] = lc;
    			else add(lc,st[top--]);
    		}
    		G[poi[i]].clear(),st[++top] = poi[i];
    	}
    	for(reg i = 1;i < top;i++) add(st[i],st[i + 1]);
    }
    inline void dfs2(int x,int f)
    {
    	dp[x] = size[x] = 0;
    	for(reg i = 0;i < G[x].size();i++)
    	{
    		int v = G[x][i];
    		if(v == f) continue;
    		dfs2(v,x);
    		dp[x] += dp[v],size[x] += size[v]; 
    	}
    	if(vis[x]) dp[x] += size[x],size[x] = 1;
    	else if(size[x] > 1) dp[x]++,size[x] = 0;
    }
    int main()
    {
    	int n = Read(1);
    	for(reg i = 1;i < n;i++)
    	{
    		int u = Read(1),v = Read(1);
    		add(u,v);
    	}
    	dep[1] = 1,dfs(1,0);
    	for(reg i = 1;i <= 18;i++)
    		for(reg j = 1;j <= n;j++)
    			fa[j][i] = fa[fa[j][i - 1]][i - 1];
    	int T = Read(1);
    	while(T--)
    	{
    		memset(vis,0,sizeof(vis));
    		int m = Read(1);
    		for(reg i = 1;i <= m;i++)
    		{
    			poi[i] = Read(1);
    			vis[poi[i]] = 1;
    		}
    		bool able = 0;
    		for(reg i = 1;i <= m;i++)
    			if(vis[fa[poi[i]][0]]&&poi[i] != 1)
    			{
    				printf("-1
    ");
    				able = 1;
    				break;
    			}
    		if(able) continue;
    		sort(poi + 1,poi + 1 + m,cmp);
    		BuildTree(m);
    		dfs2(1,0);
    		printf("%d
    ",dp[1]); 
    	}
        return 0;
    }
    
  • 相关阅读:
    100以内整数四则运算
    软件工程基础
    使用python分析微信好友
    数据库实践
    爬虫
    Python编程预测比赛成绩
    自己的第一个网页
    科学计算与可视化
    对小学生四则运算用界面呈现
    在使用memory_profiler检测python代码运行时内存出现解码错误
  • 原文地址:https://www.cnblogs.com/resftlmuttmotw/p/11707991.html
Copyright © 2011-2022 走看看