[Funny] GDSOI2019 squares [data structures] [LCT]

Description

Here Insert Picture Description
Points <= 100 000, operand <= 200000

Solution

The classic LCT maintenance sub-tree path information problems.

Specifically, we have for each node in the subtree that corresponds to splay on a strand of the original ancestor-descendant tree (root replaced), the black dots to record all point in the subtree splay and their virtual child All black dots are to 0 in the tree top views of this chain and the chain strand ancestor-descendant bottom, 1, and 2 times the distance, additional records all virtual son subtree splay the answer to this chain.

merging the two strands update corresponds to the top of the chain, for example, added directly to the left half, the right half of the distance to each of the plurality of left subtree size, using ( x + v ) 2 = x 2 + 2 x v + v 2 (x+v)^2=x^2+2xv+v^2 apart can be calculated.

While maintaining the chain to the top and bottom of the chain in reverse order when the operation can quickly find answers.

update and access times when 0 1 2 coefficient of consolidation can be removed items, can be written on a modular simpler.

time complexity O ( n log n ) O(n\log n)

Code

I do not know why not open O2 run, but ...

#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
typedef long long LL;
const int N=100005;
const int mo=998244353;
using namespace std;
int n;
LL sqr(const LL x) {return x*x;}
namespace LCT
{
	int fn[N],f[N],t[N][2],r[N];
	LL sz[N],vl[N][3],sp[N],sm[N][2][3];
	LL cl[N];
	void rev(const int k)
	{
		r[k]^=1,swap(sm[k][0],sm[k][1]);
	}
	void down(int k)
	{
		if(r[k]) 
		{
			swap(t[k][0],t[k][1]),fn[t[k][0]]=0,fn[t[k][1]]=1;
			rev(t[k][0]),rev(t[k][1]);
			r[k]=0;
		}	
	}
	void merge(LL *a,LL *b,const LL u,const LL v)
	{
		a[0]=a[0]+v*b[0];
		a[1]=a[1]+v*(b[1]+b[0]*u);
		a[2]=a[2]+v*(b[2]+b[1]*u*(LL)2+b[0]*sqr(u));
	}
	void up(int k)
	{
		if(!k) return;
		sz[k]=sz[t[k][0]]+sz[t[k][1]]+1;
		sp[k]=sp[t[k][0]]+vl[k][2]+sp[t[k][1]];
		fo(x,0,1)
		{	
			int u=t[k][x],v=t[k][1^x];
			sm[k][x][0]=cl[k],sm[k][x][1]=sz[u]*cl[k],sm[k][x][2]=sqr(sz[u])*cl[k];
			merge(sm[k][x],sm[u][x],0,1);
			merge(sm[k][x],vl[k],sz[u],1);
			merge(sm[k][x],sm[v][x],sz[u]+1,1);
		}
	}
	void hb(int x,int y,int p)
	{
		if(x&&p>=0) t[x][p]=y;
		if(y) fn[y]=p,f[y]=x;
	}
	void rot(int k)
	{
		int fa=f[k],p=fn[k];
		hb(fa,t[k][1-p],p);
		hb(f[fa],k,fn[fa]);
		hb(k,fa,1-p);
		up(fa),up(k),up(f[k]);
	}
	int d[N];
	void splay(int k,int x)
	{
		d[d[0]=1]=k;
		while(fn[d[d[0]]]!=-1&&f[d[d[0]]]!=x) d[++d[0]]=f[d[d[0]-1]];
		fod(i,d[0],1) down(d[i]);
		while(f[k]!=x&&fn[k]!=-1) 
		{
			if(fn[f[k]]==-1||f[f[k]]==x) rot(k);
			else if(fn[k]==fn[f[k]]) rot(f[k]),rot(k);
			else rot(k),rot(k);
		}
	}
	void access(int k)
	{
		int r=k;
		splay(k,0);
		merge(vl[k],sm[t[k][1]][0],1,1),hb(k,t[k][1],-1),t[k][1]=0;
		up(k);
		while(f[k])
		{
			int x=f[k];splay(x,0);
			merge(vl[x],sm[t[x][1]][0],1,1);
			merge(vl[x],sm[k][0],1,-1);
			fn[t[x][1]]=-1,hb(x,k,1),up(x),k=x;
		}
		splay(r,0);
	}
	void make(int k)
	{
		access(k),rev(k);
	}
	void link(int x,int y)
	{
		make(y),access(x);
		f[y]=x,fn[y]=-1;
		up(x);
	}
	void init()
	{
		fo(i,1,n) sz[i]=1;
		fo(i,1,n-1)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			link(x,y);
		}
	}
	void modify(int k)
	{
		make(k),cl[k]^=1,up(k);
	}
	LL query(int x,int y)
	{
		make(x),access(y);
		return sp[y];
	}
}
using namespace LCT;
int main()
{
	cin>>n;
	init();
	int q;
	cin>>q;
	fo(i,1,q)
	{	
		int tp,x,y;
		scanf("%d%d",&tp,&x);
		if(tp==0) modify(x);
		else 
		{
			scanf("%d",&y);
			printf("%lld\n",query(x,y)%mo);
		}
	}
}

Guess you like

Origin blog.csdn.net/hzj1054689699/article/details/93774716