今天专题是LCT蛤,一天其实就打了板子然后水了三道模板题,列在下面(有链接可点)
都是三道非常基础的模板题,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;
}