• [SDOI2015]寻宝游戏


    Link

    Description

     给定一棵n个点的树,树上有若干关键点。每次操作将一个关键点变成非关键点或一个非关键点变为关键点,并询问所有关键点形成的极小联通子树边权和的两倍。

    Solution

    先摆结论:

     假设树上关键点按照(dfs)序排列为{(a_1,a_2,a_3,dots,a_t)}。

     那么所有关键点形成的极小联通子树边权和的两倍会等于:

     (dis(a_1,a_2)+dis(a_2,a_3)+dots+dis(a_{t-1},a_t)+dis(a_t,a_1))

    感性偷税发现很正确。

    所以直接用一个set维护关键点按(dfs)序排列成的集合,每次加一个点x,假设其两边分别是y,z,那么答案就要加上(dis(x,y)+dis(x,z)-dis(y,z))。删掉一个点则反之。

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef set<int>::iterator sit;
    inline int read(){//be careful for long long!
        register int x=0,f=1;register char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
        while(isdigit(ch)){x=x*10+(ch^'0');ch=getchar();}
        return f?x:-x;
    }
    
    const int N=1e5+10;
    int n,m,dfn[N],idf[N],dfc,siz[N],tp[N],dep[N],fa[N],son[N],vis[N];
    ll dis[N];
    struct node{int to,val;};
    vector<node> E[N];
    set<int> s;
    inline sit pre(sit it){return --it;}
    
    inline void Dfs_1(int nw){
        dfn[nw]=++dfc,idf[dfc]=nw;
        siz[nw]=1;dep[nw]=dep[fa[nw]]+1;
        for(node i:E[nw])
    	if(i.to^fa[nw]){
    	    fa[i.to]=nw;dis[i.to]=dis[nw]+i.val;
    	    Dfs_1(i.to);siz[nw]+=siz[i.to];
    	    if(siz[i.to]>siz[son[nw]])son[nw]=i.to;
    	}
    }
    inline void Dfs_2(int nw){
        if(!tp[nw])tp[nw]=nw;
        if(son[nw]){tp[son[nw]]=tp[nw];Dfs_2(son[nw]);}
        for(node i:E[nw])
    	if(i.to^fa[nw]&&i.to^son[nw])
    	    Dfs_2(i.to);
    }
    inline ll Getdis(int x,int y){
        if(!x||!y)return 0;
        ll ans=0;
        while(tp[x]^tp[y]){
    	if(dep[tp[x]]>=dep[tp[y]])ans+=dis[x]-dis[fa[tp[x]]],x=fa[tp[x]];
    	else ans+=dis[y]-dis[fa[tp[y]]],y=fa[tp[y]];
        }
        ans+=abs(dis[x]-dis[y]);
        return ans;
    }
    
    int main(){
        n=read(),m=read();
        for(int t=1;t<n;++t){
    	int x=read(),y=read(),z=read();
    	E[x].push_back((node){y,z});E[y].push_back((node){x,z});
        }
        Dfs_1(1);Dfs_2(1);
        ll ans=0;
        for(int i=1;i<=m;++i){
    	int x=dfn[read()];
    	if(!s.size())vis[idf[x]]=1,s.insert(x);
    	else{
    	    sit it=s.lower_bound(x);
    	    int y=idf[*(it=(it==s.begin()?pre(s.end()):pre(it)))];
    	    it=s.upper_bound(x);
    	    int z=idf[*(it=(it==s.end()?s.begin():it))];
    	    x=idf[x];
    	    ll d=Getdis(x,y)+Getdis(x,z)-Getdis(y,z);
    	    if(!vis[x])ans+=d,s.insert(dfn[x]);
    	    else ans-=d,s.erase(s.find(dfn[x]));
    	    vis[x]^=1;
    	}
    	printf("%lld
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    MVC身份验证及权限管理
    EasyPR--开发详解
    ASP.NET 安全认证
    将Excel导入到数据中
    ExtJS 4 树
    ExtJS 4 表单
    ExtJS 4 Grids 详解
    ExtJS 4 类系统
    第4章 类型基础 -- 4.1 所有类型都从System.Object派生
    随滚动条浮动的链接块层
  • 原文地址:https://www.cnblogs.com/fruitea/p/12080249.html
Copyright © 2020-2023  润新知