2018.1.3学习笔记

1 篇文章 0 订阅
1 篇文章 0 订阅

今天专题是LCT蛤,一天其实就打了板子然后水了三道模板题,列在下面(有链接可点)

bzoj2631 bzoj2049 bzoj2002

都是三道非常基础的模板题,2631麻烦一些,需要维护路径权值和,还有加标记与乘标记,2049只需要查询点之间的连通性,2002则只需要维护siz就可以了

简单说一下LCT,如果splay是维护一个序列,那么LCT就是把一棵树进行链剖分,然后将每一条链用一颗splay去维护,splay的权值就是该点在原树的深度,也就是说一颗splay中,一个节点左面的节点一定比他浅,右面的节点一定比他深;

那么我们很容易就能发现LCT一些神奇的操作,LCT可以将树的形态进行任意修改,LCT的核心access操作可以将一个节点到根节点的整个链变成一颗splay,这样我们就能很轻松的维护一个链上的信息;

只扔了2631的代码,毕竟其他两道题可以通过2631很容易的改过来

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m;
unsigned int p=51061;
struct data_l{int s,t;}lin[100005];
struct data_t{int l,r,fa,rev;unsigned int siz,val,tag,tagx;bool rt;}tre[800005];
unsigned int val[200005];
data_t nx;
inline void update_rev(int x)
{
	if(!x)return;
	swap(tre[x].l,tre[x].r);
	tre[x].rev^=1;
}
inline void push_up(int x)
{
	tre[x].siz=(tre[tre[x].l].siz+tre[tre[x].r].siz+1)%p;
	tre[x].val=(tre[tre[x].l].val+tre[tre[x].r].val+val[x])%p;
}
inline void push_down(int x)
{
	if(tre[x].rev)
	{
		update_rev(tre[x].l);
		update_rev(tre[x].r);
		tre[x].rev=0;
	}
	val[tre[x].l]=(val[tre[x].l]*tre[x].tagx)%p;
	val[tre[x].r]=(val[tre[x].r]*tre[x].tagx)%p;
	tre[tre[x].l].val=tre[tre[x].l].val*tre[x].tagx%p;
	tre[tre[x].r].val=tre[tre[x].r].val*tre[x].tagx%p;
	tre[tre[x].l].tag=tre[tre[x].l].tag*tre[x].tagx%p;
	tre[tre[x].r].tag=tre[tre[x].r].tag*tre[x].tagx%p;
	tre[tre[x].l].tagx=tre[tre[x].l].tagx*tre[x].tagx%p;
	tre[tre[x].r].tagx=tre[tre[x].r].tagx*tre[x].tagx%p;
	tre[x].tagx=1;
	val[tre[x].l]=(val[tre[x].l]+tre[x].tag)%p;
	val[tre[x].r]=(val[tre[x].r]+tre[x].tag)%p;
	tre[tre[x].l].val=(tre[tre[x].l].val+tre[tre[x].l].siz*tre[x].tag%p)%p;
	tre[tre[x].r].val=(tre[tre[x].r].val+tre[tre[x].r].siz*tre[x].tag%p)%p;
	tre[tre[x].l].tag=(tre[tre[x].l].tag+tre[x].tag)%p;
	tre[tre[x].r].tag=(tre[tre[x].r].tag+tre[x].tag)%p;
	tre[x].tag=0;
}
inline void push(int x)
{
	if(!tre[x].rt)push(tre[x].fa);
	push_down(x);
}
inline void zig(int x)  
{  
	tre[0]=nx;  
	int t=tre[x].l;  
	tre[x].l=tre[t].r;  
	tre[tre[t].r].fa=x;  
	tre[t].r=x;  
	tre[t].fa=tre[x].fa;  
	tre[x].fa=t;  
	if(tre[x].rt)  
	{  
		tre[x].rt=false;  
		tre[t].rt=true;  
	}  
	else  
	{  
		if(x==tre[tre[t].fa].l)  tre[tre[t].fa].l=t;  
		else  tre[tre[t].fa].r=t;  
	}  
	push_up(x);
}
inline void zag(int x)
{
	tre[0]=nx;
	int t=tre[x].r;
	tre[x].r=tre[t].l;
	tre[tre[t].l].fa=x;
	tre[t].l=x;
	tre[t].fa=tre[x].fa;
	tre[x].fa=t;
	if(tre[x].rt)
	{
		tre[x].rt=false;
		tre[t].rt=true;
	}
	else
	{
		if(x==tre[tre[t].fa].l)  tre[tre[t].fa].l=t;
		else  tre[tre[t].fa].r=t;
	}
	push_up(x);
}
inline void splay(int x)
{
	push(x);
	while(!tre[x].rt)
	{
		int y=tre[x].fa,z=tre[y].fa;
		if(tre[y].rt)
		{
			if(x==tre[y].l)zig(y);
			else zag(y);
		}
		else if(y==tre[z].l)
		{
			if(tre[y].l==x){zig(z);zig(y);}
			else {zag(y);zig(z);}
		}
		else 
		{
			if(x==tre[y].r){zag(z);zag(y);}
			else {zig(y);zag(z);}
		}
	}
	push_up(x);
}
inline void access(int x)
{
	int y=0;
	while(x!=0)
	{
		splay(x);
		tre[tre[x].r].rt=true;
		tre[x].r=y;
		tre[y].rt=false;
		push_up(x);
		y=x;
		x=tre[x].fa;
	}
}
inline int findroot(int x)
{
	access(x);
	splay(x);
	while(tre[x].l!=0)x=tre[x].l;
	return x;
}
inline bool judge(int s,int t)
{
	s=findroot(s);t=findroot(t);
	if(s==t)return true;
	return false;
}
inline void mroot(int x)
{
	access(x);
	splay(x);
	update_rev(x);
}
inline void link(int s,int t)
{
	if(judge(s,t))return;
	mroot(s);
	tre[s].fa=t;
}
inline void cut(int s,int t)
{
	if(s==t||!judge(s,t))return;
	mroot(s);access(t);splay(t);
	tre[tre[t].l].fa=0;tre[tre[t].l].rt=true;
	tre[t].l=0;push_up(t);
}
inline int ask(int x,int y)
{
	mroot(x);
	access(y);
	splay(y);
	return (tre[tre[y].l].val+val[y])%p;
}
inline int add2(int x,int y,unsigned int xx)
{
	mroot(x);access(y);splay(y);
	val[y]=(val[y]*xx)%p;
	val[tre[y].l]=(val[tre[y].l]*xx)%p;
	tre[tre[y].l].val=tre[tre[y].l].val*xx%p;
	tre[tre[y].l].tag=(tre[tre[y].l].tag*xx)%p;
	tre[tre[y].l].tagx=(tre[tre[y].l].tagx*xx)%p;
	push_up(y);
}
inline int add1(int x,int y,int xx)
{
	mroot(x);access(y);splay(y);
	val[y]=(val[y]+xx)%p;
	val[tre[y].l]=(val[tre[y].l]+xx)%p;
	tre[tre[y].l].val=(tre[tre[y].l].val+tre[tre[y].l].siz*xx%p)%p;
	tre[tre[y].l].tag=(tre[tre[y].l].tag+xx)%p;
	push_up(y);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++)
	scanf("%d%d",&lin[i].s,&lin[i].t);
	int s,t;
	for(int i=1;i<=n;i++)
	{
		val[i]=1;
		tre[i].val=val[i];
		tre[i].siz=1;
		tre[i].rt=true;
		tre[i].tagx=1;
	}
	for(int i=1;i<n;i++)link(lin[i].s,lin[i].t);
	char xx[11];
	int s1,t1;
	for(int i=1;i<=m;i++)
	{
		scanf("%s",xx);
		if(xx[0]=='+')
		{
			scanf("%d%d%d",&s,&t,&s1);
			add1(s,t,s1);
		}
		else if(xx[0]=='-')
		{
			scanf("%d%d%d%d",&s,&t,&s1,&t1);
			cut(s,t);
			link(s1,t1);
		}
		else if(xx[0]=='*')
		{
			scanf("%d%d%d",&s,&t,&s1);
			add2(s,t,s1);
		}
		else 
		{
			scanf("%d%d",&s,&t);
			printf("%u\n",ask(s,t));
		}
		
	}
	
	return 0;
}
代码很长很丑蛤,不过容错性应该还是不错的


除了LCT今天还水了一道数学题(虽然思维并不水但代码量短的惊人)

bzoj2321星器 势能分析法

听起来逼格很高的一个算法,实际上就像是动能定理,初动能减末动能等于总能量的变化,

我们给每一颗星星附上一个状态,这个状态的权值等于他横坐标的平方加纵坐标的平方,这样我们在计算初状态和末状态的差之后得到的值的二分之一就是我们要求的值(随便推一推公式就懂了)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
int n,m,x;
ll ans;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
	{
		scanf("%d",&x);
		ans+=1ll*x*(i*i+j*j);
	}
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
	{
		scanf("%d",&x);
		ans-=1ll*x*(i*i+j*j);
	}
	printf("%lld",ans/2);
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值