暑假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\n",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\n",s.size()<=1 ? 0 : ans+get_it(mp[*s.begin()],mp[*--s.end()]));
    }
}
View Code
posted @ 2019-07-28 21:40  _JSQ  阅读(173)  评论(0编辑  收藏  举报