1. 程式人生 > 其它 >Loj#3511【USACO 2021 Open, P】T1 United Cows of Farmer John

Loj#3511【USACO 2021 Open, P】T1 United Cows of Farmer John

【USACO 2021 Open, P】T1 United Cows of Farmer John

題目連結

題目大意

\(N\)​ 頭奶牛,每條隊伍的隊頭和隊尾都與隊伍中其他牛的種類不同,還需選出隊伍中的一個作為領隊,也需與其他牛種類不同。

求方案數。 \(N \le 2e5\)

解法

將三個領隊分別稱作領頭、領隊和領尾。

先不考慮領隊。

線段樹維護兩個值:區間內的 領頭數量 和 領頭和領尾匹配對數(領尾範圍無限制)。

具體是對於每次加入一個點,將對應 \(b_i\) 的上一個領頭刪掉,並使所有 \(g_{l,r}+=f_{l,r}\) ,將當前點記作新的領頭。

然後考慮對於一個領隊位置為 \(K\)

,最長的有效區間設為 \(\left[ L, R \right]\) ,用 做到R時\(g_{L,K}\) 減去做到K時 \(g_{L,K}\) 為答案。

code

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define ll long long
#define ls (t<<1)
#define rs (t<<1|1)
using namespace std;
const ll N=2e5+10;
ll n,a[N],ans,f[N<<2],g[N<<2],tag[N<<2];
ll t[N],l[N],r[N],cnt,Ans[N];
struct node{
	ll t,v,l,r,id;
}b[N*2];
bool cmp(node a,node b){return a.t<b.t;}
void push(ll t){
	g[ls]+=f[ls]*tag[t];
	g[rs]+=f[rs]*tag[t];
	tag[ls]+=tag[t];tag[rs]+=tag[t];
	tag[t]=0;
}
void add(ll t,ll l,ll r,ll L,ll R){
	if(L<=l && r<=R){
		g[t]+=f[t];
		++tag[t];
		return;
	}
	ll mid=l+r>>1;
	if(L<=mid)add(ls,l,mid,L,R);
	if(R>mid)add(rs,mid+1,r,L,R);
	g[t]=g[ls]+g[rs];
}
void modify(ll t,ll l,ll r,ll x,ll y){
	f[t]+=y;
	if(l==r)return;
	if(tag[t])push(t);
	ll mid=l+r>>1;
	if(x>mid)modify(rs,mid+1,r,x,y);
	else modify(ls,l,mid,x,y);
}
ll query(ll t,ll l,ll r,ll L,ll R){
	if(L<=l && r<=R)return g[t];
	if(tag[t])push(t);
	ll mid=l+r>>1,ret=0;
	if(L<=mid)ret+=query(ls,l,mid,L,R);
	if(R>mid)ret+=query(rs,mid+1,r,L,R);
	return ret;
}
int main(){
	scanf("%lld",&n);
	fo(i,1,n){
		scanf("%lld",&a[i]);
		l[i]=t[a[i]];
		t[a[i]]=i;
	}
	fo(i,1,n)t[i]=n+1;
	fd(i,n,1){
		r[i]=t[a[i]];
		t[a[i]]=i;
	}
	fo(i,2,n-1){
		ll L=l[i]+1,R=r[i]-1;
		if(L<i && i<R){
			b[++cnt]=(node){i,-1,L,i-1,i};
			b[++cnt]=(node){R,1,L,i-1,i};
		}
	}
	sort(b+1,b+cnt+1,cmp);
	for(ll i=1,it=1;i<=cnt && it<=cnt;++i){
		if(l[i])modify(1,1,n,l[i],-1);
		if(l[i]+1<i)add(1,1,n,l[i]+1,i-1);
		modify(1,1,n,i,1);
		for(;it<=cnt && b[it].t==i;++it){
			ans+=b[it].v*query(1,1,n,b[it].l,b[it].r);
			Ans[b[it].id]+=b[it].v*query(1,1,n,b[it].l,b[it].r);
		}
	}
	printf("%lld\n",ans);
//	fo(i,1,n)printf("%lld ",Ans[i]);
//	printf("\n");
	
	return 0;
}