码迷,mamicode.com
首页 > 其他好文 > 详细

「USACO 2021 US Open Platinum」United Cows of Farmer John

时间:2021-05-24 07:42:42      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:oid   ==   线段   class   turn   一个   出现   printf   结构   

「USACO 2021 US Open Platinum」United Cows of Farmer John

考虑依次枚举右端点\(i\),计算左边合法的方案数,设一个数\(x\)上次出现的位置为\(lst_x\)

\(i\)能够作为右端点的区间就是\([lst_{a_i}+1,i-2]\)

考虑什么样的位置可以作为左端点,显然这个点在\([1,i]\)中是最后一次出现

我们将不妨这样的点权值设为\(w_i=1\)

考虑一个点作为中间点贡献怎样的区间,同样的,这个点在\([1,i]\)中是最后一次出现

并且,能够贡献的区间\(>\)上一次出现的位置\(lst_x\)

这个中间点能够匹配的左端点个数就是\(\displaystyle \sum_{k=lst_{a_j}+1}^{j-1} w_k\)

现在我们要用数据结构动态修改某一个位置的\(w_i\),增减\([lst_{a_j}+1,j-1]\)的区间,查询\([lst_{a_i}+1,i-2]\)

不妨再为一个点增加点权\(t_i\),此时我们要维护的操作

1.单点修改\(w_i\)

2.区间修改\(t_i\)

3.求\(w_it_i\)区间和

在线段树上每个节点维护\(w_i\)之和,\(w_it_i\)之和,可以标记永久化\(t_i\)

具体实现参考代码(实际写得很丑)

const int N=2e5+10,INF=1e9+10;


int n;
int lst[N],lst2[N],cnt;
ll s1[N<<2],s2[N<<2];
int t[N<<2];
// s1表示w之和,s2表示区间内部t[i]*w[i]之和,t[i]现在是永久化的标记
void Up(int p){
	s2[p]=s2[p<<1]+s2[p<<1|1];
	s1[p]=s1[p<<1]+s1[p<<1|1]+s2[p]*t[p];
}
void Upd(int p,int l,int r,int x){
	if(l==r) {
		s2[p]^=1,s1[p]=t[p]*s2[p];
		return;
	}
	int mid=(l+r)>>1;
	x<=mid?Upd(p<<1,l,mid,x):Upd(p<<1|1,mid+1,r,x);
	Up(p);
}

void Upd(int p,int l,int r,int ql,int qr,int x){
	if(ql>qr) return;
	if(ql<=l && r<=qr) {
		t[p]+=x,s1[p]+=x*s2[p];
		return;
	}
	int mid=(l+r)>>1;
	if(ql<=mid) Upd(p<<1,l,mid,ql,qr,x);
	if(qr>mid) Upd(p<<1|1,mid+1,r,ql,qr,x);
	Up(p);
}

struct Node{
	ll x,y;
	Node(ll x=0,ll y=0):x(x),y(y){  }
	Node operator + (const Node __) { return Node(x+__.x,y+__.y); }
};
Node Que(int p,int l,int r,int ql,int qr){
	if(ql>qr) return Node();
	if(ql<=l && r<=qr) return Node(s1[p],s2[p]);
	int mid=(l+r)>>1; Node res;
	if(ql<=mid) res=res+Que(p<<1,l,mid,ql,qr);
	if(qr>mid) res=res+Que(p<<1|1,mid+1,r,ql,qr);
	res.x+=res.y*t[p];
	return res;
}

int main(){
	n=rd();
	ll ans=0;
	rep(i,1,n) {
		int x=rd();
		if(lst[x]) {
			Upd(1,1,n,lst[x]),cnt--;
			Upd(1,1,n,lst2[x]+1,lst[x],-1);
		}
		Node t=Que(1,1,n,lst[x]+1,i-2);
		ans+=t.x;
		Upd(1,1,n,i),cnt++,Upd(1,1,n,lst[x]+1,i-1,1);
		lst2[x]=lst[x],lst[x]=i;
	}
	printf("%lld\n",ans);
}

「USACO 2021 US Open Platinum」United Cows of Farmer John

标签:oid   ==   线段   class   turn   一个   出现   printf   结构   

原文地址:https://www.cnblogs.com/chasedeath/p/14764083.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!