zoukankan      html  css  js  c++  java
  • CF1344E Train Tracks

    Train Tracks

    There are (n) stations and (m) trains. The stations are connected by (n-1) one-directional railroads that form a tree rooted at station (1). All railroads are pointed in the direction from the root station (1) to the leaves. A railroad connects a station (u) to a station (v), and has a distance (d), meaning it takes (d) time to travel from (u) to (v). Each station with at least one outgoing railroad has a switch that determines the child station an incoming train will be directed toward.

    Initially, no trains are at any station. Train (i) will enter station (1) at time (t_i). Every unit of time, starting at time (1), the following two steps happen:

    1. You can switch at most one station to point to a different child station. A switch change takes effect before step 2.

    2. For every train that is on a station (u), it is directed toward the station (v) indicated by (u)'s switch. So, if the railroad from (u) to (v) has distance (d), the train will enter station (v) in (d) units of time from now.

    Every train has a destination station (s_i). When it enters (s_i), it will stop there permanently. If at some point the train is going in the wrong direction, so that it will never be able to reach (s_i) no matter where the switches point, it will immediately explode.

    Find the latest possible time of the first explosion if you change switches optimally, or determine that you can direct every train to its destination so that no explosion occurs. Also, find the minimum number of times you need to change a switch to achieve this.

    (1leq n,mleq 10^5)

    题解

    https://codeforces.com/blog/entry/76819

    First, observe that a train can never pass one that enters earlier. So let's consider the trains independently. For a train (i), look at the path from (1) to (s_i). We may need to change the switches of several stations on this path. We must make each switch within a time interval ((L, R]), where (L) is the most recent time some other train was directed the other way, and (R) is the time train (i) will enter the station. Let's mark all of these switches as changed before processing the next train.

    Suppose the total number of switch changes is (k), and for each station, we know its time intervals. We can manage all events in a priority queue of size (n), always changing the switch with the earliest deadline that we can. Keep doing this until we are too late for a deadline, in which case an explosion happens, or until we have successfully made every switch change. This part will take (O(klog n)) time.

    扫描线+贪心选取右端点最小的。

    Let's find a nice upper bound on (k). Note that the switches decompose the tree into a set of disjoint paths. When we process a train (i), we are changing the switches to make a path from the root to (s_i). It turns out this is exactly the same as an access operation on a link/cut tree! Because link/cut trees have (O(log n)) amortized time per operation, we can guarantee that the total number of switch changes is (k=O(n+mlog n)).

    access操作访问虚边的复杂度是多少呢?https://www.cnblogs.com/reverymoon/p/10086216.html

    我们定义势能函数(phi),为所有重虚边(儿子的子树大小大于等于自己的二分之一的虚边)的数量。

    那么,每次访问至多走(log)条轻虚边,也就至多带来(log)条重虚边,也就是以(O(log))的代价增加(log)的势能。

    而每次访问一条重虚边就需要付出(O(1))的代价来减小(1)的势能,并且访问完重虚边之后,不会有新的重虚边产生。

    因此,最终的复杂度是初始势能和势能变化量(实际操作的代价和势能变化量相同)的和,也就是(O(n+mlog n))

    Now let's consider the problem of finding all time intervals. We could use a link/cut tree……

    The overall complexity is (O(nlog n+mlog^2 n)).

    CO int N=1e5+10;
    struct edge {int v;int64 w;};
    vector<edge> to[N];
    int64 dis[N];
    
    void dfs(int u){
    	for(CO edge&e:to[u]) dis[e.v]=dis[u]+e.w,dfs(e.v);
    }
    
    int ch[N][2],fa[N];
    int64 tim[N],tag[N];
    
    IN bool nroot(int x){
    	return ch[fa[x]][0]==x or ch[fa[x]][1]==x;
    }
    void push_down(int x){
    	if(tag[x]!=-1){
    		if(ch[x][0]) tim[ch[x][0]]=tag[ch[x][0]]=tag[x];
    		if(ch[x][1]) tim[ch[x][1]]=tag[ch[x][1]]=tag[x];
    		tag[x]=-1;
    	}
    }
    void rotate(int x){
    	int y=fa[x],z=fa[y],l=x==ch[y][1],r=l^1;
    	if(nroot(y)) ch[z][y==ch[z][1]]=x; fa[x]=z;
    	ch[y][l]=ch[x][r],fa[ch[x][r]]=y;
    	ch[x][r]=y,fa[y]=x;
    }
    void splay(int x){
    	vector<int> stk={x};
    	for(int i=x;nroot(i);) stk.push_back(i=fa[i]);
    	for(;stk.size();stk.pop_back()) push_down(stk.back());
    	for(;nroot(x);rotate(x)){
    		int y=fa[x],z=fa[y];
    		if(nroot(y)) rotate((x==ch[y][1])!=(y==ch[z][1])?x:y);
    	}
    }
    
    struct node {int64 l,r;};
    vector<node> buc;
    priority_queue<int64,vector<int64>,greater<int64> > heap;
    
    int main(){
    //	freopen("E.in","r",stdin),freopen("E.out","w",stdout);
    	int n=read<int>(),m=read<int>();
    	for(int i=1;i<n;++i){
    		int u=read<int>(),v=read<int>();
    		to[u].push_back({v,read<int64>()});
    		ch[u][1]=v,fa[v]=u;
    	}
    	dfs(1);
    	for(int i=1;i<=n;++i) tim[i]=-dis[i],tag[i]=-1;
    	while(m--){
    		int s=read<int>();
    		int64 t=read<int64>();
    		splay(s);
    		for(int x=fa[s],y=s;x;y=x,x=fa[x]){
    			splay(x),ch[x][1]=y;
    			buc.push_back({tim[x]+dis[x]+1,t+dis[x]});
    //			cerr<<x<<" l="<<tim[x]+dis[x]+1<<" r="<<t+dis[x]<<endl;
    		}
    		splay(s);
    		if(ch[s][0]) tim[ch[s][0]]=tag[ch[s][0]]=t;
    	}
    	sort(buc.begin(),buc.end(),[&](CO node&a,CO node&b)->bool{
    		return a.l<b.l;
    	});
    	int64 now=1; int cnt=0;
    	for(int i=0;i<(int)buc.size();++i){
    		for(;buc[i].l>now and heap.size();heap.pop()){
    			int64 r=heap.top();
    			if(now>r){
    				for(int j=0;j<i;++j) cnt-=buc[j].r>=r;
    				for(;heap.size();heap.pop()) cnt+=heap.top()>=r;
    				printf("%lld %d
    ",r,cnt);
    				return 0;
    			}
    			now=now+1,++cnt;
    		}
    		if(buc[i].l>now) now=buc[i].l;
    		heap.push(buc[i].r);
    	}
    	for(;heap.size();heap.pop()){
    		int64 r=heap.top();
    		if(now>r){
    			for(int i=0;i<(int)buc.size();++i) cnt-=buc[i].r>=r;
    			for(;heap.size();heap.pop()) cnt+=heap.top()>=r;
    			printf("%lld %d
    ",r,cnt);
    			return 0;
    		}
    		now=now+1,++cnt;
    	}
    	printf("-1 %d
    ",cnt);
    	return 0;
    }
    
    
  • 相关阅读:
    windows下基于IIS配置ssl证书
    IIS HTTP重定向到HTTPS
    C#:调用存储过程方法
    IIS无法启动解决方案
    C#工具:ASP.net 调用MySQL 帮助类(包括存储过程调用)
    C#工具:ASP.net 调用SQLserver帮助类
    HTTPClick调用WebApi帮助类
    三元运算符判断三种状态
    pandas模块
    numpy模块
  • 原文地址:https://www.cnblogs.com/autoint/p/12852796.html
Copyright © 2011-2022 走看看