异象石
给定一个支持增加和删除的点集,求将点集联通的边集的最小值
引理: 将点按照dfn环排列后 求相邻两点的距离和就是答案的二倍
尝试证明:
我们发现dfn相对大的节点 他们的了lca的的dfn就相对较小
如果一个节点的祖先的链上,经过dfn小的一定会经过dfn大的
对于三个点\(a,b,c\),我们假设\(dfn[a]<dfn[b] dfn[c]\)
有\(dfn[lca(b,c)] \le dfn[lca(a,b)]\) 设置为\(m_1,m_2\)
从a的角度来看:\(m_1,m_2\)都是a的祖先
\(a \rightarrow b : a\rightarrow m_1 \rightarrow b\)
\(a \rightarrow c : a\rightarrow m_1 \rightarrow m_2 \rightarrow b\)
因此一定会覆盖两遍
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
using namespace std;
const int N=1e5+10;
typedef long long ll;
int read()
{
	int x=0,f=0,c=getchar();
	while(c<'0'||c>'9'){if(c=='-') f=1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return f?-x:x;
}
struct Edge
{
	int to,next,w;
}e[N*2];
int head[N],cnt;
void _add(int a,int b,int c){ e[++cnt]=(Edge){b,head[a],c}; head[a]=cnt;}
void add(int a,int b,int c){ _add(a,b,c); _add(b,a,c);}
int sz[N],top[N],fa[N],son[N],dfn[N];
ll dep[N];
int tim;
void dfs1(int x)
{
	sz[x]=1; dfn[x]=++tim;
	for(int i=head[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if(y==fa[x]) continue;
		dep[y]=dep[x]+e[i].w; fa[y]=x; 
		dfs1(y);
		sz[x]+=sz[y];
		if(sz[son[x]]<sz[y]) son[x]=y;
	}
}
void dfs2(int x,int tp)
{
	top[x]=tp;
	if(son[x]) dfs2(son[x],tp);
	for(int i=head[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if(y==fa[x]||y==son[x]) continue;
		dfs2(y,y);
	}
}
struct Node{ int id,tim;};
bool operator<( const Node &a,const Node &b){ return a.tim<b.tim;}
set< Node > s;
typedef set<Node>::iterator It;
int LCA(int x,int y)
{
	while(top[x]!=top[y])
		dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
	return dep[x]<dep[y]?x:y;
}
ll getdis(int x,int y) { return dep[x]+dep[y]-2*dep[LCA(x,y)];}
ll upd(int x)
{
	if(s.size()==1) return 0;
	It it=s.find( (Node){x,dfn[x]} ); It tmp=it; It pre,nxt;
	if(tmp==s.begin()) pre=--s.end(),nxt=++tmp;
	else if(tmp==--s.end()) pre=--tmp,nxt=s.begin();
	else pre=--tmp,tmp++,nxt=++tmp;
	return getdis(pre->id,it->id)+getdis(it->id,nxt->id)-getdis(pre->id,nxt->id);
}
int n,m;
ll ans;
int main()
{
	n=read(); 
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read(),z=read();
		add(x,y,z);
	}
	m=read();
	dfs1(1);  dfs2(1,1);
	while(m--)
	{
		char c=getchar();
		if(c=='?') printf("%lld\n",ans>>1),getchar();
		else
		{
			int x=read();
			if(c=='+') 
			{
				s.insert( (Node){x,dfn[x]} );
				ans=ans+upd(x);
			}
			else ans=ans-upd(x),s.erase( (Node){x,dfn[x]} );
		}
	}
	return 0;
}
点集问题按照dfn排序后再考虑 可能会有特殊性质
 
                    
                
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号