• [SDOI2015]寻宝游戏


    Description

    2019-09-20 10-12-59 的屏幕截图.png

    Soluiton

    结论1:(x_1, x_2, x_3, x_4, cdots x_k) 到根的路径的并的和等于把 (x_1, x_2cdots x_k)(dfn) 排序后所有点到根的 (dis) 减去相邻两个点 LCA 到根的 (dis)

    证明:考虑用增量法,已知有两点 (x_1, x_3)(x_2) 插入在 (x_1, x_3) 之间(dfn序位于 (x_1)(x_3) 之间),那么 (x_2)(LCA(x_1, x_3)) 的子树内,假设 (LCA(x_3, x_1) = LCA(x_2, x_3)) 此时原来的 (dis(x_1) + dis(x_3) - dis(LCA(x_1,x_3))) 就要变成 (dis(x_1) + dis(x_3) - dis(LCA(x_1, x_3)) + dis(x_2) - dis(LCA(x_1, x_2)) = dis(x_1) + dis(x_2) + dis(x_3) - dis(LCA(x_1, x_2)) - dis(LCA(x_2, x_3)))

    (x) 插入开头和结尾的时候类似可证。

    结论2:(x_1, x_2,cdots ,x_k) 的 LCA 为他们按 dfn 排序后开头和结尾两点的 LCA。

    证明:由 dfn 序的性质,中间的点 (x_2,cdots x_{k-1}) 都在 (LCA(x_1, x_k)) 的子树内。

    回到本题

    不难发现就是要我们求若干个点 (x_1, cdots ,x_k)(LCA(x_1, cdots, x_k)) 路径的并。

    有上面那两个结论就很好做了,把这 (k) 个点按 dfn 序排序。

    那么答案为:

    [egin{aligned} &2left(left(sum_{i=1}^k dis(x_i) ight) -left(sum_{i=1}^{k-1}dis(LCA(x_i,x_{i+1})) ight) - dis(LCA(x_1,x_k)) ight)\ =&2left(frac{1}{2}sum_{i=1}^{k-1}dis(x_i)+dis(x_{i+1})-2dis(LCA(x_i,x_{i+1})) ight) + dis(x_1) + dis(x_k) - 2dis(LCA(x_1, x_k))\ =&sum_{i=1}^{k-1}dis(x_i,x_{i+1})+dis(x_1,x_k) end{aligned} ]

    于是用set维护dfn序删除和加点就查前驱后继。

    code

    #include <iostream>
    #include <set>
    #include <cassert>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <fstream>
    
    using namespace std;
    
    #define LL long long
    #define SZ(x) ((int)x.size())
    #define ALL(x) (x).begin(), (x).end()
    #define MP(x, y) std::make_pair(x, y)
    #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
    #define REP(i, a, b) for (register int (i) = (a); (i) <= (b); ++(i))
    #define GO cerr << "GO" << endl;
    
    inline void proc_status()
    {
    	ifstream t("/proc/self/status");
    	cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>()) << endl;
    }
    template<class T> inline T read() 
    {
    	register char c;
    	register T x(0), f(1);
    	while (!isdigit(c = getchar())) if (c == '-') f = -1;
    	while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));
    	return x * f;
    }
    template<typename T> inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
    template<typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
    
    const int maxN=1e5;
    
    int n,m;
    int ver[maxN*2],nxt[maxN*2],edge[maxN*2],head[maxN+1],tot;
    int dfn[maxN+2],f[maxN+2][19],dep[maxN+2],dfst,rev[maxN+2];
    bool vis[maxN+2];
    LL dis[maxN+2];
    set<int> s;
    
    void link(int u,int v,int w)
    {
    	ver[++tot]=v,nxt[tot]=head[u],edge[tot]=w,head[u]=tot;
    }
    
    void DFS(int u,int fa)
    {
    	dfn[u]=++dfst;
    	rev[dfst]=u;
    	dep[u]=dep[fa]+1;
    	f[u][0]=fa;
    	for(int i=1;i<18;++i)
    		f[u][i]=f[f[u][i-1]][i-1];
    	for(int i=head[u];i;i=nxt[i])
    	{
    		int v=ver[i];
    		if (v==fa)continue;
    		dis[v]=dis[u]+edge[i];
    		DFS(v,u); 
    	}
    }
    
    int GetLca(int u, int v)
    {
    	if(dep[u]<dep[v])
    		swap(u,v);
    	for(int i=17;i>=0;--i)
    		if(dep[f[u][i]]>=dep[v])
    			u=f[u][i];
    	assert(dep[u]==dep[v]);
    	if(u==v)return u;
    	for(int i=17;i>=0;--i)
    		if(f[u][i]!=f[v][i])
    			u=f[u][i],v=f[v][i];
    	assert(f[u][0]==f[v][0]);
    	return f[u][0];
    }
    
    LL GetDis(int u, int v)
    {
    	int Lca=GetLca(u,v);
    	return dis[u]+dis[v]-dis[Lca]*2;
    }
    
    #define Iter set<int>::iterator
    
    LL ans(0);
    Iter it;
    
    int main() 
    {
    #ifndef ONLINE_JUDGE
    	freopen("xhc.in", "r", stdin);
    	freopen("xhc.out", "w", stdout);
    #endif
    	n=read<int>(),m=read<int>();
    	for(int i=1;i<n;++i)
    	{
    		int u=read<int>(),v=read<int>(),w=read<int>();
    		link(u,v,w),link(v,u,w);
    	}
    	DFS(1,0);
    	for(int i=1;i<=m;++i)
    	{
    		int x=read<int>();
    		if(!vis[x])
    		{
    			vis[x]=1;
    			if(s.size()==0)
    			{
    				s.insert(dfn[x]);
    				printf("%lld
    ",ans);
    				continue;
    			}
    			Iter n=s.lower_bound(dfn[x]);
    			if(n==s.end())
    			{
    				Iter p=n;p--;
    				ans+=GetDis(x,rev[*p])+GetDis(x,rev[*s.begin()])-GetDis(rev[*s.begin()],rev[*p]);
    				s.insert(dfn[x]);
    			}else if(n==s.begin())
    			{
    				ans+=GetDis(x,rev[*n])+GetDis(x,rev[*s.rbegin()])-GetDis(rev[*n],rev[*s.rbegin()]);
    				s.insert(dfn[x]);
    			}else
    			{
    				Iter p=n;p--;
    				ans+=GetDis(x,rev[*p])+GetDis(x,rev[*n])-GetDis(rev[*p],rev[*n]);
    				s.insert(dfn[x]);
    			}
    		}
    		else
    		{
    			vis[x]=0;
    			if(s.size()==1)
    			{
    				s.erase(dfn[x]);
    				ans=0;
    				printf("%lld
    ",ans);
    				continue;
    			}
    			Iter cur=s.find(dfn[x]);
    			Iter n=cur;n++;
    			if(n==s.end())
    			{
    				Iter p=cur;p--;
    				ans-=GetDis(x,rev[*p])+GetDis(x,rev[*s.begin()])-GetDis(rev[*s.begin()],rev[*p]);
    				s.erase(dfn[x]);
    			}else if(cur==s.begin())
    			{
    				ans-=GetDis(x,rev[*n])+GetDis(x,rev[*s.rbegin()])-GetDis(rev[*n],rev[*s.rbegin()]);
    				s.erase(dfn[x]);
    			}else
    			{
    				Iter p=cur;p--;
    				ans-=GetDis(x,rev[*p])+GetDis(x,rev[*n])-GetDis(rev[*p],rev[*n]);
    				s.erase(dfn[x]);
    			}
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    JSP动作元素你又知几多?
    一个简单的TCP/IP服务端客户端对话
    使用Graphics2D去除曲线锯齿状
    MySQL数据类型
    Eclipse常用快捷键
    C#中的委托和事件
    GitHub当道,菜鸟也为Git疯狂
    C++文件操作
    JSP指令你知多少?
    spring如何使用多个xml配置文件
  • 原文地址:https://www.cnblogs.com/cnyali-Tea/p/11555432.html
Copyright © 2020-2023  润新知