zoukankan      html  css  js  c++  java
  • LOJ3278 收获

    收获

    IOI 庄园有 (N) 个员工,(M) 棵苹果树种在湖岸。湖的周长为 (L) 米。

    一开始员工 (i) 位于从湖的最北端向顺时针方向前进 (A_i) 米处,所有 (A_i) 互异。苹果树 (j) 生长在从湖的最北端向顺时针方向前进 (B_j) 米处,所有 (B_j) 互异。

    每棵苹果树最多长一个苹果,收获后 (C) 秒会长出一个新的。时刻 (0) 时,所有的苹果树上都有一个苹果。员工从时刻 (0) 开始从各自的地点以 (1 ext{m/s}) 的速度顺时针前进,遇到成熟的苹果就将其摘下(若到达时刚长出苹果,也要摘下),摘苹果的时间忽略不计。

    现给出 (Q) 个询问,第 (k) 次询问员工 (V_k) 在时刻 (T_k) 结束时一共收获到几个苹果。

    对于 (100\%) 的数据,(1 leq N,M leq 2 imes 10^5)(N+M leq L leq 10^9)(1 leq C leq 10^9)(1 leq Q leq 2 imes 10^5)

    题解

    https://www.cnblogs.com/dysyn1314/p/12582983.html

    果树和人是相对运动的,因为是对人做询问,所以可以考虑让人不动,果树运动。这样的好处是可以把人的结构固定下来,便于用数据结构维护。

    具体来讲,对于所有(iin[1,n]),我们从第(i)个人向逆时针方向第一个到他的距离(geq C)的人(j)连边。表示某棵果树被(i)摘掉后,下一个摘的人是(j)。边权是这两次采摘的时间间隔。

    对于每棵果树,向它逆时针方向的第一个人连边。表示它的果子第一次是被这个人摘到的。边权是这个人到这棵果树的距离。

    因为每个点都有且仅有一条出边,于是,我们得到了一个基环内向树森林。其中,每棵果树是一个叶子,其他节点都是人。开始时,果树会从它所在的叶子出发,经过每条边需要一定的时间。我们要回答(Q)次询问,问在某一时刻之前某个节点共被果树经过了多少次(同一棵果树如果多次经过同一节点,则每次都要被算在答案里)。

    先把询问离线下来。给每个节点开一个vector,存关于这个节点的询问。

    基环树森林里的每棵基环树显然相互独立。我们对分别对每棵基环树计算答案。

    对于一棵基环树,我们先断掉它环上的一条边。然后分两种情况讨论:

    • 果树到达被询问节点时,之前没有经过被断掉的这条边。

    • 果树到达被询问节点时,之前经过了被断掉的这条边。注意,因为是在环上,所以有可能多次经过。

    对于第一种情况,答案显然是树上(基环树断掉一条边后会变成普通的树)某个子树内,深度不超过某个值的果树数量。用DFS序把“子树”转化成一段区间,问题变为简单的二维数点问题。具体来说,我们把所有的果树和询问放在一起,按深度排序。每次加入一个点,或询问一个区间内的点数。可以用树状数组维护。

    对于第二种情况。我们先把每棵果树移动到被断掉的这条边的终点。对于第(i)棵果树,设它移动到这个点所花费的时间为(t_i)。设要回答的询问时间为(T)。则对答案的贡献是(sum_{t_ileq T}frac{T-t_i}{len})。其中(len)是基环树的环长。这里的除法取整是一个细节。如果余数大于等于被断掉的边的终点被询问的节点的距离,则上取整,否则下去整。设这个距离为(d),则我们也可以形式化地把这个式子写作:

    [sum_{t_ileq T}(lfloorfrac{T-t_i}{len} floor+[(T-t_i)mod len>dmod len])=sum_{t_ileq T}lfloorfrac{T-t_i+len-d}{len} floor ]

    其实这也是一个二维数点问题。先把果树和询问一起按时间排序。我们可以用两个变量(num,sum),分别记录已经扫描到的果树的数量,和果树的(lfloorfrac{t_i}{len} floor)之和。对于某个查询(x=T+len-d),先令答案等于(lfloorfrac{x}{len} floorcdot num-sum)。这样会多计算的是(t_imod len)大于(xmod len)的这些果树(每棵这样的果树会使答案被多算(1))。我们事先把所有余数离散化一下,然后在树状数组上做单点修改、后缀和查询即可。

    时间复杂度(O(nlog n))

    CO int N=2e5+10;
    int A[N],B[N];
    pair<int,int> fa[N];
    vector<pair<int,int> > to[N],val[N],que[N];
    
    pair<int,int> ban;
    int L[N],R[N],dfn,dep[N];
    
    struct event {int o,x,t;};
    vector<event> F,G;
    
    void dfs(int x,int fa){
    	L[x]=++dfn;
    	for(CO pair<int,int>&v:val[x])
    		F.push_back({0,L[x],dep[x]+v.second});
    	for(CO pair<int,int>&e:to[x])if(e.first!=fa){
    		if(x==ban.first and e.first==ban.second) continue;
    		dep[e.first]=dep[x]+e.second;
    		dfs(e.first,x);
    	}
    	R[x]=dfn;
    	for(CO pair<int,int>&q:que[x]){
    		F.push_back({-q.first,L[x]-1,dep[x]+q.second});
    		F.push_back({q.first,R[x],dep[x]+q.second});
    	}
    }
    
    namespace bit{
    	int n,S[2*N];
    	
    	IN void init(int n){
    		bit::n=n,fill(S,S+n+1,0);
    	}
    	void insert(int p,int v){
    		for(int i=p;i<=n;i+=i&-i) S[i]+=v;
    	}
    	int query(int p){
    		int ans=0;
    		for(int i=p;i;i-=i&-i) ans+=S[i];
    		return ans;
    	}
    }
    
    int64 ans[N];
    
    signed main(){
    	int n=read<int>(),m=read<int>();
    	int L=read<int>(),C=read<int>();
    	function<int(int,int)> dist=[&](int x,int y)->int{ // clockwise
    		return x<=y?y-x:L+y-x;
    	};
    	for(int i=1;i<=n;++i) read(A[i]);
    	for(int i=1;i<=n;++i){
    		int A0=((A[i]-C)%L+L)%L;
    		fa[i].first=upper_bound(A+1,A+n+1,A0)-A-1; // find the next
    		if(!fa[i].first) fa[i].first=n;
    		fa[i].second=dist(A[fa[i].first],A0)+C;
    		to[fa[i].first].push_back({i,fa[i].second});
    	}
    	for(int i=1;i<=m;++i){
    		read(B[i]);
    		int x=upper_bound(A+1,A+n+1,B[i])-A-1;
    		if(!x) x=n;
    		val[x].push_back({i,dist(A[x],B[i])});
    	}
    	int q=read<int>();
    	for(int i=1;i<=q;++i){
    		int x=read<int>(),T=read<int>();
    		que[x].push_back({i,T});
    	}
    	
    	for(int i=1;i<=n;++i)if(!::L[i]){
    		static bool vis[N];
    		int x=i;
    		for(;!vis[x];x=fa[x].first) vis[x]=1;
    		ban={fa[x].first,x};
    		
    		dfn=0,F.clear(),dfs(x,0);
    		sort(F.begin(),F.end(),[&](CO event&a,CO event&b)->bool{
    			return a.t!=b.t?a.t<b.t:abs(a.o)<abs(b.o);
    		});
    		bit::init(dfn);
    		for(CO event&f:F){
    			if(f.o==0) bit::insert(f.x,1);
    			else if(f.o<0) ans[-f.o]-=bit::query(f.x);
    			else ans[f.o]+=bit::query(f.x);
    		}
    		
    		G.clear();
    		for(CO event&f:F)if(f.o==0)
    			G.push_back({0,0,f.t+fa[x].second}); // t_i
    		int p=fa[x].first,len=0;
    		while(1){
    			for(CO pair<int,int>&q:que[p])if(q.second>=len)
    				G.push_back({q.first,0,q.second-len}); // T-d
    			len+=fa[p].second,p=fa[p].first;
    			if(p==fa[x].first) break;
    		}
    		sort(G.begin(),G.end(),[&](CO event&a,CO event&b)->bool{
    			return a.t!=b.t?a.t<b.t:abs(a.o)<abs(b.o);
    		});
    		vector<int> tmp;
    		for(event&g:G){
    			if(g.o>0) g.t+=len; // T+len-d
    			tmp.push_back(g.t%len);
    		}
    		sort(tmp.begin(),tmp.end());
    		tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());
    		for(event&g:G)
    			g.x=lower_bound(tmp.begin(),tmp.end(),g.t%len)-tmp.begin()+1;
    		bit::init(tmp.size());
    		int64 sum=0,num=0;
    		for(CO event&g:G){
    			if(g.o==0){
    				bit::insert(g.x,1);
    				sum+=g.t/len,++num;
    			}
    			else{
    				ans[g.o]+=g.t/len*num-sum;
    				ans[g.o]-=bit::query(tmp.size())-bit::query(g.x);
    			}
    		}
    	}
    	for(int i=1;i<=q;++i) printf("%lld
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    [CF1076D] Edge Deletion
    [CF1081D] Maximum Distance
    [CF1095F] Make It Connected
    [CF1328E] Tree Queries
    [CF1328F] Make k Equal
    Codeforces Round #629 (Div. 3) 总结
    [CF1131D] Gourmet choice
    [CF1176D] Recover it!
    [CF1205B] Shortest Cycle
    [CF1213G] Path Queries
  • 原文地址:https://www.cnblogs.com/autoint/p/12693056.html
Copyright © 2011-2022 走看看