jzoj6257. 【省选模拟8.9】修路

Description
在这里插入图片描述

Input
在这里插入图片描述

Output
在这里插入图片描述

Sample Input
Sample Input 1
5
1 2 3 4 5
1 2
2 3
2 4
3 5

Sample Input 2
10
1 7 3 4 8 6 2 9 10 5
1 2
1 3
2 4
3 5
2 6
3 7
4 8
5 9
6 10

Sample Output
Sample Output 1
0
0
0
2

Sample Output 2
0
0
0
1
1
0
1
2
3

Data Constraint
在这里插入图片描述

题解

可以发现染色操作类似LCT
而LCT的时间复杂度(操作的splay树总数)为n log n,对应本题就是总操作颜色块为n log n
所以LCT维护颜色+树状数组算答案

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define low(x) (x&-(x))
using namespace std;

struct type{
	int s,id;
} A[100001];
int tr[100001][4]; //2=size 3=color
int fa[100001];
int C[100001];
int p[100001][2];
long long Tr[100001];
int n,i,j,k,l,I,x,y;
long long ans;

bool cmp(type a,type b)
{
	return a.s<b.s;
}

void rot(int t)
{
	int Fa=fa[t],Fa2=fa[Fa],s,x,x2;
	
	x=tr[Fa][1]==t;
	x2=tr[Fa2][1]==Fa;
	
	s=tr[t][x^1];
	
	tr[t][3]=tr[Fa][3];
	tr[Fa][3]=0;
	
	tr[Fa][2]=tr[tr[Fa][x^1]][2]+tr[tr[t][x^1]][2]+1;
	tr[t][2]=tr[tr[t][x]][2]+tr[Fa][2]+1;
	
	fa[s]=Fa;
	tr[Fa][x]=s;
	
	fa[Fa]=t;
	tr[t][x^1]=Fa;
	
	fa[t]=Fa2;
	if (!tr[t][3])
	tr[Fa2][x2]=t;
}

void splay(int t)
{
	int Fa,Fa2;
	
	while (!tr[t][3])
	{
		Fa=fa[t];
		
		if (!tr[Fa][3])
		{
			Fa2=fa[Fa];
			
			if ((tr[Fa2][0]==Fa)^(tr[Fa][0]==t)==1)
			rot(t),rot(t);
			else
			rot(Fa),rot(t);
		}
		else
		rot(t);
	}
}

void change(int t,int s)
{
	while (t<=n)
	{
		Tr[t]+=s;
		t+=low(t);
	}
}

long long find(int t)
{
	long long ans=0;
	
	while (t)
	{
		ans+=Tr[t];
		t-=low(t);
	}
	
	return ans;
}

int main()
{
	freopen("road.in","r",stdin);
	freopen("road.out","w",stdout);
	
	scanf("%d",&n);
	fo(i,1,n)
	{
		scanf("%d",&C[i]);
		
		A[i].s=C[i];
		A[i].id=i;
	}
	
	sort(A+1,A+n+1,cmp);
	
	j=0;
	fo(i,1,n)
	{
		if (i==1 || A[i].s!=A[i-1].s)
		++j;
		C[A[i].id]=j;
	}
	
	fo(i,1,n)
	{
		tr[i][2]=1;
		tr[i][3]=C[i];
	}
	
	fo(I,2,n)
	{
		scanf("%d%d",&x,&y);
		
		l=0;
		
		i=x;
		j=0;
//		access
		while (i)
		{
			splay(i);
			
			tr[i][2]-=tr[tr[i][1]][2];
			tr[tr[i][1]][3]=tr[i][3];
			
			tr[i][1]=0;
			
			++l;
			p[l][0]=tr[i][3];
			p[l][1]=tr[i][2];
			
			if (j)
			{
				tr[i][1]=j;
				
				tr[j][3]=0;
				tr[i][2]+=tr[j][2];
			}
			
			j=i;
			i=fa[i];
		}
		tr[j][3]=C[y];
		fa[y]=x;
		
		ans=0;
		fo(i,1,l)
		{
			ans+=find(p[i][0]-1)*p[i][1];
			change(p[i][0],p[i][1]);
		}
		
		printf("%lld\n",ans);
		
		fo(i,1,l)
		change(p[i][0],-p[i][1]);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值