连环病原体,洛谷P4230,LCT+二维前缀和

正题

      可以发现对于每一个l,找到最小的r,使[l,r]为一个加强区间,那么r是关于l单调不降的.

      证明显然.那么我们就可以用LCT来two-pointers.

      得到一个区间,考虑会对什么位置的ans产生贡献,发现可以对[l,r]中的ans贡献m-r+1,对[r+1,m]中的ans贡献一个首项为m-r,公差为-1的一个等差数列,如何区间加等差数列,二维前缀和即可,具体来说就是差分两次,转化为给4个位置加一个权值.

总结

      二维前缀和和two-pointers都是极其经典的算法值得经常回顾.

#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
using namespace std;

const int N=400010,M=200010;
struct node{
	int son[2],fa;
	bool swp;
}s[N];
pair<int,int> p[M];
long long sum[M];
int m;

#define ls s[x].son[0]
#define rs s[x].son[1]
#define n 400000
bool isrt(int x) {return s[s[x].fa].son[0]!=x && s[s[x].fa].son[1]!=x;}
void psd(int x){
	if(s[x].swp){
		s[x].swp^=1;s[ls].swp^=1;s[rs].swp^=1;
		swap(s[ls].son[0],s[ls].son[1]);
		swap(s[rs].son[0],s[rs].son[1]);
	}
}

void rotate(int x){
	int f=s[x].fa,ff=s[f].fa;
	bool w=s[f].son[1]==x;
	if(!isrt(f)) s[ff].son[s[ff].son[1]==f]=x;s[x].fa=ff;
	s[f].son[w]=s[x].son[w^1];s[s[x].son[w^1]].fa=f;
	s[f].fa=x;s[x].son[w^1]=f;
}

void dfs(int x){if(!isrt(x)) dfs(s[x].fa);psd(x);}
void splay(int x){
	dfs(x);
	while(!isrt(x)){
		int f=s[x].fa,ff=s[f].fa;
		if(!isrt(f)) s[ff].son[1]==f^s[f].son[1]==x?rotate(x):rotate(f);
		rotate(x);
	}
}

void acs(int x){for(int las=0;x;las=x,x=s[x].fa) splay(x),s[x].son[1]=las;}
void mkrt(int x){acs(x);splay(x);s[x].swp^=1;swap(ls,rs);}
void split(int x,int y){mkrt(x);acs(y);splay(y);}
int findrt(int x){acs(x);splay(x);while(s[x].son[0]) x=s[x].son[0];splay(x);return x;}
bool link(int x){
	mkrt(p[x].first);
	if(findrt(p[x].second)==p[x].first) return false;
	split(p[x].first,p[x].second);s[p[x].first].fa=p[x].second;
	return true;
}
void cut(int x,int y){split(x,y);s[y].son[0]=s[x].fa=0;}
void add(int x,int y,int fir,int d){
	if(x>y) return;
	sum[x]+=fir;sum[x+1]+=d-fir;
	sum[y+1]-=fir+1ll*(y-x+1)*d;sum[y+2]+=fir+1ll*(y-x)*d;
}

int main(){
	scanf("%d",&m);
	for(int i=1;i<=m;i++) scanf("%d %d",&p[i].first,&p[i].second);
	int l=1,r=0;
	while(l<=m){
		while(r<m && link(r+1)) r++;
		if(r==m) break;
		add(l,r+1,m-r,0);add(r+2,m,m-r-1,-1);
		cut(p[l].first,p[l].second);l++;
	}
	for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
	for(int i=1;i<=m;i++) sum[i]+=sum[i-1],printf("%lld ",sum[i]);
}

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/108351548