zoukankan      html  css  js  c++  java
  • 【BZOJ】3991: [SDOI2015]寻宝游戏

    题意

    给一个(n)个点带边权的树。有(m)次操作,每一次操作一个点(x),如果(x)已经出现,则(x)消失。否则(x)出现。每一操作后,询问从某个点开始走,直到经过所有出现的点,最后再回到开始的那个点的最短路程。

    分析

    首先容易知道我们选任意一个在某两点路径上的点作为起点都能得到最优解(包括端点)。我们只需要考虑走的顺序。

    题解

    由于按照dfs序的走法是最短的,因此我们按dfs序维护一下前前后后的距离和即可。如何证明?好像并不会...

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=100005;
    int n, ihead[N], FF[N], dep[N], cnt, a[N], fa[N][17], m;
    ll d[N];
    struct E {
    	int next, to, w;
    }e[N<<1];
    struct dat {
    	int FF, id;
    	ll dis;
    	bool operator < (const dat &a) const {
    		return FF<a.FF;
    	}
    };
    set<dat> s;
    void add(int x, int y, int w) {
    	e[++cnt]=(E){ihead[x], y, w}; ihead[x]=cnt;
    	e[++cnt]=(E){ihead[y], x, w}; ihead[y]=cnt;
    }
    void dfs(int x, int f=0) {
    	static int fid=0;
    	FF[x]=++fid;
    	for(int i=1; i<=16; ++i) {
    		fa[x][i]=fa[fa[x][i-1]][i-1];
    	}
    	for(int i=ihead[x]; i; i=e[i].next) {
    		int y=e[i].to;
    		if(y==f) {
    			continue;
    		}
    		fa[y][0]=x;
    		dep[y]=dep[x]+1;
    		d[y]=d[x]+e[i].w;
    		dfs(y, x);
    	}
    }
    int LCA(int x, int y) {
    	if(dep[x]<dep[y]) {
    		swap(x, y);
    	}
    	int d=dep[x]-dep[y];
    	for(int i=16; i>=0; --i) if((d>>i)&1) x=fa[x][i];
    	if(x==y) return x;
    	for(int i=16; i>=0; --i) if(fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i];
    	return fa[x][0];
    }
    ll getdis(int x, int y) {
    	int lca=LCA(x, y);
    	return d[x]+d[y]-(d[lca]<<1);
    }
    int main() {
    	scanf("%d%d", &n, &m);
    	for(int i=1; i<n; ++i) {
    		int x, y, w;
    		scanf("%d%d%d", &x, &y, &w);
    		add(x, y, w);
    	}
    	dfs((n+1)>>1);
    	ll ans=0;
    	while(m--) {
    		int p;
    		scanf("%d", &p);
    		dat t;
    		if(a[p]) {
    			set<dat>::iterator it=s.lower_bound((dat){FF[p], 0, 0}), itp=s.end(), itb=s.end();
    			itb=it;
    			++itb;
    			ans-=it->dis;
    			if(it!=s.begin()) {
    				itp=it;
    				--itp;
    			}
    			if(itb!=s.end()) {
    				ans-=itb->dis;
    				if(itp==s.end()) {
    					t=*itb;
    					t.dis=0;
    					s.erase(itb);
    					s.insert(t);
    				}
    				else {
    					t=*itb;
    					t.dis=getdis(itb->id, itp->id);
    					ans+=t.dis;
    					s.erase(itb);
    					s.insert(t);
    				}
    			}
    			s.erase(it);
    			a[p]=0;
    		}
    		else {
    			set<dat>::iterator it=s.lower_bound((dat){FF[p], 0, 0}), itp=s.end();
    			if(it!=s.begin()) {
    				itp=it;
    				--itp;
    			}
    			if(it!=s.end()) {
    				if(itp!=s.end()) {
    					ll dis=getdis(p, itp->id);
    					s.insert((dat){FF[p], p, dis});
    					ans+=dis;
    				}
    				else {
    					s.insert((dat){FF[p], p, 0});
    				}
    				t=*it;
    				ans-=t.dis;
    				t.dis=getdis(p, it->id); 
    				ans+=t.dis;
    				s.erase(it);
    				s.insert(t);
    			}
    			else {
    				if(itp==s.end()) {
    					s.insert((dat){FF[p], p, 0});
    				}
    				else {
    					ll dis=getdis(p, itp->id);
    					s.insert((dat){FF[p], p, dis});
    					ans+=dis;
    				}
    			}
    			a[p]=1;
    		}
    		ll temp=0;
    		if(s.size()>=2) {
    			set<dat>::iterator it=s.end();
    			--it;
    			temp=getdis(s.begin()->id, it->id);
    		}
    		printf("%lld
    ", ans+temp);
    	}
    	return 0;
    }
  • 相关阅读:
    HDU5890:Eighty seven(Bitset优化背包)
    AtCoder3857:Median Sum (Bitset优化背包&&对称性求中位数)
    POJ3275:Ranking the Cows(Bitset加速floyd求闭包传递)
    Gym
    POJ2443 Set Operation (基础bitset应用,求交集)
    POJ2976:Dropping tests(01分数规划入门)
    HihoCoder1084: 扩展KMP(二分+hash,求T串中S串的数量,可以失配一定次数)
    扩展KMP(占位)
    MySQL主备模式的数据一致性解决方案
    MaxCompute问答整理之6月
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4986317.html
Copyright © 2011-2022 走看看