HDU 5296 Annoying problem dfs序+lca

题意:
给你一棵树,然后你有一个空的集合,能对集合进行两个操作
1.添加一个点到集合内
2.删除一个点从集合内
输出集合内的点按lca来连接出来的树形图的权值和

思路:
没思路…..QAQ
get一个公式就是在树上求点到链的公式
就x到链(u,v)
Dis=dis[x]-dis[lca(x,u)]-dis[lca(x,v)]+dis[lca(u,v)]
它确实是对的,但是我没有推出来怎么证明的….(如果有巨巨知道请告知一下…
添加点的时候就添加dfs序比x大的最小一个和比x小最大的一个,
如果某一个不存在就去集合内dfs序最大和最小的两个点的链到x的距离
话说这个set

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<bitset>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x&(-x))
typedef long long LL;
const int maxn = 100005;
const int inf=(1<<28)-1;
vector<pair<int,int> >vec[maxn];
map<int,int>Map;
int In[maxn],Out[maxn],tot,deep[maxn];
int ft[maxn][20],Pow[20],dis[maxn];
void dfs(int u,int fa,int dep)
{
    In[u]=++tot;
    Map[tot]=u;
    deep[u]=dep;
    for(int i=1;i<20;++i)
    {
        if(dep<Pow[i])
            break;
        ft[u][i]=ft[ft[u][i-1]][i-1];
    }
    int Size=vec[u].size();
    for(int i=0;i<Size;++i)
    {
        int v=vec[u][i].first;
        if(v!=fa)
        {
            ft[v][0]=u;
            dis[v]=dis[u]+vec[u][i].second;
            dfs(v,u,dep+1);
        }
    }
    Out[u]=tot;
}
int lca(int u,int v)
{
    if(deep[u]<deep[v])
        swap(u,v);
    int t=deep[u]-deep[v];
    for(int i=0;i<20;++i)
    if(t&Pow[i])
        u=ft[u][i];
    for(int i=19;i>=0;--i)
    if(ft[u][i]!=ft[v][i])
    {
        u=ft[u][i];
        v=ft[v][i];
    }
    if(u==v)
        return u;
    return ft[u][0];
}
set<int>Set1;
set<int>::iterator it1;
set<int,greater<int> >Set2;
set<int,greater<int> >::iterator it2;
int main()
{
    Pow[0]=1;
    for(int i=1;i<20;++i)
        Pow[i]=Pow[i-1]*2;
    int T,Case=0;
    scanf("%d",&T);
    while(T--)
    {
        printf("Case #%d:\n",++Case);
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;++i)
            vec[i].clear();
        for(int i=1;i<n;++i)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            vec[u].push_back(make_pair(v,w));
            vec[v].push_back(make_pair(u,w));
        }
        tot=0;
        dis[1]=0;
        Set1.clear();
        Set2.clear(); 
        Map.clear();
        memset(ft,0,sizeof(ft));
        dfs(1,-1,0);
        LL Ans=0;
        while(q--)
        {
            int chs,x;
            scanf("%d%d",&chs,&x);
            if(chs==1)
            {
                if(Set1.count(In[x]))
                {
                    printf("%lld\n",Ans);
                    continue;
                }
                if(Set1.empty())
                {
                    Set1.insert(In[x]);
                    Set2.insert(In[x]);
                    printf("0\n");
                    continue;
                }
                it1=Set1.upper_bound(In[x]);
                it2=Set2.upper_bound(In[x]);
                if(it1==Set1.end()||it2==Set2.end())
                    it1=Set1.begin(),it2=Set2.begin();
                int u=Map[*it1],v=Map[*it2];
                //printf("***%d %d\n",u,v);
                Ans+=dis[x]-dis[lca(u,x)]-dis[lca(v,x)]+dis[lca(u,v)];
                //printf("***%d %d %d\n",lca(u,x),lca(v,x),lca(u,v));
                Set1.insert(In[x]);
                Set2.insert(In[x]);
                printf("%lld\n",Ans);
            }
            else
            {
                if(!Set1.count(In[x]))
                {
                    printf("%lld\n",Ans);
                    continue;
                }
                Set1.erase(In[x]);
                Set2.erase(In[x]);
                if(Set1.empty())
                {
                    printf("0\n");
                    continue;
                }
                it1=Set1.upper_bound(In[x]);
                it2=Set2.upper_bound(In[x]);
                if(it1==Set1.end()||it2==Set2.end())
                    it1=Set1.begin(),it2=Set2.begin();
                int u=Map[*it1],v=Map[*it2];
                //printf("***%d %d\n",u,v);
                Ans-=dis[x]-dis[lca(u,x)]-dis[lca(v,x)]+dis[lca(u,v)];
                printf("%lld\n",Ans);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值