• 暑假D14 T3 cruise(SDOI2015 寻宝游戏)(虚树+set)


    题意

    给出一棵树,从中选出一些点,有m次操作改变点的状态(有->没有,没有->有)并输出经过全部点至少经过多少路径。

    对于100%的数据,1≤n,m≤200000,1≤x,y,Ai≤n

    题解

    先考虑寻宝游戏那道题,要回到原点,可以证明答案的两倍为按DFS序排序后相邻两个选择点的距离和加上首尾点的距离。(我不会,之后再填坑)

    那现在再看这道题,会发现就是上面答案的一半。(我也不会证)

    set是像平衡树一样的东西,可以支持插入、删除、查找、求前驱后继,插入之后就是按从小到大排序

    本题

    #include<bits/stdc++.h>
    using namespace std;
    //路径条数就是(按dfs序走的路径+首尾两点路径)的一半 
    const int maxn=200005;
    int n,m,cnt,ans;
    int id[maxn],mp[maxn],a[maxn];
    int fa[maxn][21],dis[maxn];
    vector<int>e[maxn];
    set<int> s;
    set<int>::iterator it;
    
    template<class T>inline void read(T &x){
        x=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    }
    
    void dfs(int u){
        id[u]=++cnt;
        mp[cnt]=u;
        for(int i=1;i<=18;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
        for(unsigned int i=0;i<e[u].size();i++){
            int v=e[u][i];
            if(v==fa[u][0]) continue;
            fa[v][0]=u;
            dis[v]=dis[u]+1;
            dfs(v);
        } 
    }
    
    int lca(int x,int y){
        if(dis[x]>dis[y]) swap(x,y);
        int delt=dis[y]-dis[x];
        for(int i=0;delt;i++,delt>>=1)
         if(delt&1) y=fa[y][i];
        if(x==y) return x;
        for(int i=18;fa[x][0]!=fa[y][0];i--)
         if(fa[x][i]!=fa[y][i])
          x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    
    int get_it(int x,int y){
        return dis[x]+dis[y]-2*dis[lca(x,y)];
    } 
    
    int pre(int x){
        it=s.find(id[x]);
        return it==s.begin() ? 0 : mp[*--it];
    }
    
    int nxt(int x){
        it=s.find(id[x]);
        return ++it==s.end() ? 0 : mp[*it];
    }
    
    void ins(int x){
        s.insert(id[x]);
        int l=pre(x),r=nxt(x);
        if(l) ans+=get_it(l,x);
        if(r) ans+=get_it(x,r);
        if(l&&r) ans-=get_it(l,r);
    }
    
    void del(int x){
        int l=pre(x),r=nxt(x);
        if(l) ans-=get_it(l,x);
        if(r) ans-=get_it(x,r);
        if(l&&r) ans+=get_it(l,r);
        s.erase(id[x]);
    }
    
    int main(){
        freopen("cruise.in","r",stdin);
        freopen("cruise.out","w",stdout);
        read(n);read(m);
        for(int i=1;i<n;i++){
            int x,y;
            read(x);read(y);
            e[x].push_back(y);
            e[y].push_back(x);
        }
        dfs(1);
        for(int i=1;i<=n;i++){
            read(a[i]);
            if(a[i]) ins(i);
        }
        for(int i=1;i<=m;i++){
            int x;read(x);
            a[x] ? del(x) : ins(x);
            a[x]^=1;
            printf("%d
    ",s.size()<=1 ? 0 : (ans+get_it(mp[*s.begin()],mp[*--s.end()]))>>1);
        }
    }
    View Code

    寻宝游戏

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int maxn=200005;
    int n,m,cnt;
    int id[maxn],mp[maxn],a[maxn];
    int fa[maxn][21],dep[maxn];
    ll dis[maxn],ans;
    vector<pair<int,ll> >e[maxn];
    set<int> s;
    set<int>::iterator it;
    
    template<class T>inline void read(T &x){
        x=0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    }
    
    void dfs(int u){
        id[u]=++cnt;
        mp[cnt]=u;
        for(int i=1;i<=18;i++) fa[u][i]=fa[fa[u][i-1]][i-1];
        for(unsigned int i=0;i<e[u].size();i++){
            int v=e[u][i].first;
            if(v==fa[u][0]) continue;
            fa[v][0]=u;
            dis[v]=dis[u]+e[u][i].second;
            dep[v]=dep[u]+1;
            dfs(v);
        } 
    }
    
    int lca(int x,int y){
        if(dep[x]>dep[y]) swap(x,y);
        int delt=dep[y]-dep[x];
        for(int i=0;delt;i++,delt>>=1)
         if(delt&1) y=fa[y][i];
        if(x==y) return x;
        for(int i=18;fa[x][0]!=fa[y][0];i--)
         if(fa[x][i]!=fa[y][i])
          x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    
    ll get_it(int x,int y){
        return dis[x]+dis[y]-2*dis[lca(x,y)];
    } 
    
    int pre(int x){
        it=s.find(id[x]);
        return it==s.begin() ? 0 : mp[*--it];
    }
    
    int nxt(int x){
        it=s.find(id[x]);
        return ++it==s.end() ? 0 : mp[*it];
    }
    
    void ins(int x){
        s.insert(id[x]);
        int l=pre(x),r=nxt(x);
        if(l) ans+=get_it(l,x);
        if(r) ans+=get_it(x,r);
        if(l&&r) ans-=get_it(l,r);
    }
    
    void del(int x){
        int l=pre(x),r=nxt(x);
        if(l) ans-=get_it(l,x);
        if(r) ans-=get_it(x,r);
        if(l&&r) ans+=get_it(l,r);
        s.erase(id[x]);
    }
    
    int main(){
        read(n);read(m);
        for(int i=1;i<n;i++){
            int x,y;
            ll z;
            read(x);read(y);read(z);
            e[x].push_back(make_pair(y,z));
            e[y].push_back(make_pair(x,z));
        }
        dep[1]=1;
        dfs(1);
        for(int i=1;i<=m;i++){
            int x;read(x);
            a[x] ? del(x) : ins(x);
            a[x]^=1;
            printf("%lld
    ",s.size()<=1 ? 0 : ans+get_it(mp[*s.begin()],mp[*--s.end()]));
        }
    }
    View Code
  • 相关阅读:
    JZOJ6096 森林
    HIT暑期集训 二分图匹配
    HIT暑期集训 网络流
    HIT暑期集训 tarjan,dfs序
    HIT暑期集训 图论基础
    HIT暑期集训 AC自动机
    HIT第二周 周测补题
    HIT暑期集训 字符串
    HIT暑期集训 动态规划
    HIT暑期集训 平衡树
  • 原文地址:https://www.cnblogs.com/sto324/p/11261043.html
Copyright © 2020-2023  润新知