题意
给出一棵树,从中选出一些点,有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); } }
寻宝游戏
#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()])); } }