[SCOI2015]國旗計劃(可能是倍增)

題目
這個題要是真的打倍增就是思維僵化,莫得洗白。
如果把每個[li,ri][l_i,r_i],對於ri>=lj and li<ljr_i >= l_j \ and \ l_i < l_j並且在此基礎上滿足rjr_j最大的jj(i,j)(i,j)我們連邊(i,j)(i,j),我們把環拆成長度爲2n2n的鏈後這種連邊就會連出來一棵樹,那麼每個點ii的答案就是祖先中最後一個與ii距離<=<=一個環長的點與ii在樹上的深度差。
所以解法一:樹上DFS+當前弧優化 O(n)O(n)
大佬代碼
解法二:排序求出樹上點反向拓撲序即可用並查集優化。
AC Code\rm AC \ Code

#include<bits/stdc++.h>
#define maxn 400005
using namespace std;

int n,m,p,c[maxn],d[maxn],id[maxn],ans[maxn];
bool cmp(const int &u,const int &v){ return c[u]<c[v]; }
int F[maxn],D[maxn];
int Find(int u){
	int t = F[u];
	if(t<p) F[u] = Find(t) , D[u] += D[t];
	return F[u];
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d%d",&c[i],&d[i]),id[i]=i,(d[i]<c[i]?d[i]+=m:0);
	sort(id+1,id+1+n,cmp);
	for(int i=1;i<=n;i++) id[i+n]=id[i]+n,c[i+n]=c[i]+m,d[i+n]=d[i]+m;
	for(int i=1,j=2;i<=2*n;i++){
		for(;j<=2*n && c[id[j]] <= d[id[i]];j++);
		F[i] = j-1 , D[i] = 1;
	}
	for(int i=1;i<=n;i++){
		p=i+n,Find(i);
		ans[id[i]] = D[i];
	}
	for(int i=1;i<=n;i++) printf("%d%c",ans[i]," \n"[i==n]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章