原题传送门
终于下定决心来开这个坑
看看我在中考前能写多少分吧。。。
UPD:完成成就(^o^)/~
先把GDSOI第四题写完吧。。。
带轮换的树上路径求和
具体来说是写两棵splay,分别维护编号和权值
我们只需要保证这两棵splay的形态是一致的,再维护一下对应根的关系
这样就可以很容易地解决编号的问题了
这样有41分
cmoplete 5.28 10:00
把取下整写出来
具体过程就暴力开方
如果发现最大值等于最小值
或者最大值和最小值的差为1
就打标记然后退出
不要忘了把最后访问的点splay到根
这样有 65分
complete 5.28 11:10
学习类欧
UPD:5.28 16:00
走之前终于调出来了
显然要对于所有的点都成立的话那么求的那两个数分别是最大值和最小值
即 max/p<u/v<min/q
如果 max/p>min/q 那么就是求 min/q<u/v<max/p
也就是我们要求一个 a/b<u/v<c/d ,最小化u
其实最小化分子和分母是一样的
那么我们可以这样考虑,如果a>=b,那么我们把不等式左右同时减去 ⌊ab⌋
那么就得到了一个新的不等式 a′/b<u′/v<c′/d
如果这时候c’>d了那么u’,v就可以等于1了
如果不行那么我们就把不等式翻过来变成 d/c′<v/u′<b/a′
这样递归下去进行就可以了
边界还有一个是a=0
可以发现每次减小的意义就是把a变成a%b,所以这个算法是类欧几里得算法
复杂度是O(log n)的
complete 76分
UPD: 6.5
大概就是对于每一个点维护一个siz表示它所有原树中的虚儿子的子树大小之和
然后在虚实交替的时候维护一下siz就可以了
发现这样子的话link和cut是和深度有关的
所以有必要要学习一下另一种link和cut的姿势_ (:з」∠) _
UPD:6.13
终于调出来了QwQ
get成就手调LCT
但是还不是很熟还需要多加练习
注意虚实交替的时候这两个点一定要是原树上的父亲和儿子
就是这个splay的中序遍历的第一个
然后注意虚实交替的时候那两个点是否在同一个splay上,如果是后面断掉这条边就要小心
在调试的时候发现栋栋数据有点弱。。。。
所有的1操作都是加上之前断掉的那条边。。。。
所以我的link和cut写错了我都不知道QwQ
不能保证link和cut的正确性,错了欢迎打脸
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a) for(int i=last[a];i;i=next[i])
using namespace std;
typedef long long ll;
const int N=2*1e4+5,inf=0x7fffffff;
int t[N*2],next[N*2],last[N],a[N],size[N],n,m,x,y,z,u,v,p,q,l,opt,root;
struct LCT{
int t[2][N][2],f[2][N],g[2][N],size[2][N],p[N],d[N];
ll sum[2][N],key[2][N],lazy[2][N],mx[2][N],mi[2][N];
int rev[2][N],same[2][N];
int siz[2][N],s[2][N];
void newnode(int x,int y) {
p[x]=y;g[0][x]=g[1][x]=x;
size[0][x]=size[1][x]=1;
same[0][x]=same[1][x]=-1;
key[1][x]=sum[1][x]=mx[1][x]=mi[1][x]=a[x];
}
void add(int bz,int x,int y) {
if (!x) return;
sum[bz][x]+=(ll)size[bz][x]*y;
key[bz][x]+=y;lazy[bz][x]+=y;
mx[bz][x]+=y;mi[bz][x]+=y;
}
void makesame(int bz,int x,int y) {
if (!x) return;
sum[bz][x]=(ll)size[bz][x]*y;
key[bz][x]=y;same[bz][x]=y;
mx[bz][x]=mi[bz][x]=y;
lazy[bz][x]=0;
}
void updata(int bz,int x) {
if (!x) return;
s[bz][x]=s[bz][t[bz][x][0]]+s[bz][t[bz][x][1]]+siz[bz][x];
size[bz][x]=size[bz][t[bz][x][0]]+size[bz][t[bz][x][1]]+1;
sum[bz][x]=key[bz][x]+sum[bz][t[bz][x][0]]+sum[bz][t[bz][x][1]];
mx[bz][x]=max(key[bz][x],max(mx[bz][t[bz][x][0]],mx[bz][t[bz][x][1]]));
mi[bz][x]=min(key[bz][x],min(mi[bz][t[bz][x][0]],mi[bz][t[bz][x][1]]));
}
void down(int bz,int x) {
if (rev[bz][x]) {
swap(t[bz][x][0],t[bz][x][1]);
rev[bz][t[bz][x][0]]^=1;rev[bz][t[bz][x][1]]^=1;
rev[bz][x]=0;
}
if (same[bz][x]!=-1) {
makesame(bz,t[bz][x][0],same[bz][x]);
makesame(bz,t[bz][x][1],same[bz][x]);
same[bz][x]=-1;
}
if (lazy[bz][x]) {
add(bz,t[bz][x][0],lazy[bz][x]);
add(bz,t[bz][x][1],lazy[bz][x]);
lazy[bz][x]=0;
}
}
void remove(int bz,int x,int y) {
do {
d[++d[0]]=x;
x=f[bz][x];
} while (x!=y);
while (d[0]) down(bz,d[d[0]--]);
}
int son(int bz,int x) {
return t[bz][f[bz][x]][1]==x;
}
void rotate(int bz,int x) {
int y=f[bz][x],z=son(bz,x),u=g[bz][y];f[bz][x]=f[bz][y];
if (u) g[1-bz][u]=x,g[bz][x]=u,g[bz][y]=0;
if (t[bz][x][1-z]) f[bz][t[bz][x][1-z]]=y;
if (f[bz][y]) t[bz][f[bz][y]][son(bz,y)]=x;
else if (!bz) p[x]=p[y],p[y]=0;
t[bz][y][z]=t[bz][x][1-z];t[bz][x][1-z]=y;f[bz][y]=x;
updata(bz,y);updata(bz,x);
}
void splay(int bz,int x,int y) {
remove(bz,x,y);
while (f[bz][x]!=y) {
if (f[bz][f[bz][x]]!=y)
if (son(bz,x)==son(bz,f[bz][x])) rotate(bz,f[bz][x]);
else rotate(bz,x);
rotate(bz,x);
}
}
int kth(int bz,int x,int sz) {
if (!x) return 0;down(bz,x);
if (size[bz][t[bz][x][0]]+1==sz) return x;
if (size[bz][t[bz][x][0]]+1>sz) return kth(bz,t[bz][x][0],sz);
else return kth(bz,t[bz][x][1],sz-size[bz][t[bz][x][0]]-1);
}
int find(int x) {
splay(0,x,0);splay(1,g[0][x],0);
return kth(1,g[0][x],size[0][t[0][x][0]]+1);
}
int getsize(int x) {
splay(0,x,0);
return siz[0][x]+s[0][t[0][x][1]]+size[0][t[0][x][1]]+1;
}
void real_empty(int x,int y) {
if (!y) return;
splay(0,y,0);
siz[0][x]+=getsize(y);
updata(0,x);
}
void empty_real(int x,int y) {
if (!y) return;
splay(0,y,0);
siz[0][x]-=getsize(y);
updata(0,x);
}
void access(int x) {
int y=0,yy=0;
while (x) {
splay(0,x,0);int xx=find(x);splay(1,xx,0);
int z=t[0][x][1],zz=t[1][xx][1];
int u=kth(0,z,1);
if (u) {
real_empty(x,u);
splay(0,x,0);splay(0,u,x);
f[0][u]=0;t[0][x][1]=0;p[u]=x;
z=u;
}
int v=kth(0,y,1);
if (v) {
empty_real(x,v);
splay(0,v,0);
f[0][v]=x;t[0][x][1]=v;p[v]=0;
y=v;
}
if (z) g[0][z]=zz;
if (zz) g[1][zz]=z;
f[1][zz]=0;t[1][xx][1]=0;
t[1][xx][1]=yy;f[1][yy]=xx;
g[0][x]=xx;g[1][xx]=x;
g[0][y]=g[1][yy]=0;
updata(0,x);updata(1,xx);
y=x;yy=xx;x=p[x];
}
}
void makeroot(int x) {
access(x);splay(0,x,0);
int y=find(x);splay(1,y,0);
rev[0][x]^=1;rev[1][y]^=1;
}
void reverse(int x,int y) {
int u=kth(1,x,1),v=kth(1,x,size[1][x]);
if (u==v) return;
splay(1,u,0);f[1][t[1][u][1]]=0;t[1][u][1]=0;
splay(1,v,0);t[1][v][1]=u;f[1][u]=v;g[0][y]=v;
updata(1,u);updata(1,v);
}
void link(int x,int y) {
makeroot(x);makeroot(y);
access(x);splay(0,x,0);
siz[0][x]+=getsize(y);
updata(0,x);p[y]=x;
}
void cut(int x,int y) {
makeroot(x);access(x);splay(0,x,0);
siz[0][x]-=getsize(y);updata(0,x);
splay(0,y,0);p[y]=0;
}
void work(int x,int y) {
if (!x) return;
if (y>z) z=y,v=x;
down(1,x);
int a=mx[1][x],b=mi[1][x],c=floor(sqrt(a)),d=floor(sqrt(b));
if (a==b) {
makesame(1,x,c);
return;
}
if (a==b+1) {
if (c==d) makesame(1,x,c);
else add(1,x,c-a);
return;
}
key[1][x]=floor(sqrt(key[1][x]));
work(t[1][x][0],y+1);work(t[1][x][1],y+1);
updata(1,x);
}
int get(int x,int y) {
makeroot(x);access(y);splay(0,y,0);
int u=find(y);splay(1,u,0);
return u;
}
}tr;
void add(int x,int y) {
t[++l]=y;next[l]=last[x];last[x]=l;
}
void dfs(int x,int y) {
tr.newnode(x,y);
rep(i,x) if (t[i]!=y) {
dfs(t[i],x);
tr.siz[0][x]+=tr.siz[0][t[i]]+1;
}
tr.s[0][x]=tr.siz[0][x];
}
int gcd(int x,int y) {return y?gcd(y,x%y):x;}
void likegcd(int a,int b,int c,int d,int &u,int &v) {
if (!a) {
u=1;v=ceil(d*1.0/c);
return;
}
int uu,vv;
if (a>=b) {
likegcd(a%b,b,c-d*(a/b),d,uu,vv);
u=uu+vv*(a/b);v=vv;
} else if (c<=d) {
likegcd(d,c,b,a,uu,vv);
u=vv;v=uu;
} else u=v=1;
}
int main() {
freopen("satori.in","r",stdin);
freopen("satori.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n-1) scanf("%d%d",&x,&y),add(x,y),add(y,x);
fo(i,1,n) scanf("%d",&a[i]);
dfs(1,0);root=1;tr.mi[1][0]=inf;
for(;m;m--) {
scanf("%d",&opt);
if (opt==1) {
scanf("%d%d",&x,&y);
tr.cut(x,y);
scanf("%d%d",&u,&v);
tr.link(u,v);
}
if (opt==2) {
scanf("%d",&x);
root=x;
}
if (opt==3) {
scanf("%d%d%d",&x,&y,&z);
int u=tr.get(x,y);
tr.add(1,u,z);
}
if (opt==4) {
scanf("%d%d",&x,&y);
int u=tr.get(x,y);
tr.reverse(u,y);
}
if (opt==5) {
scanf("%d%d",&x,&y);
int u=tr.get(x,y);
z=0;tr.work(u,1);
tr.splay(1,v,0);
}
if (opt==6) {
scanf("%d%d",&x,&y);
int u=tr.get(x,y);
printf("%lld\n",tr.sum[1][u]);
}
if (opt==7) {
scanf("%d%d%d%d",&x,&y,&p,&q);
int u=tr.get(x,y);
int a=tr.mx[1][u],b=tr.mi[1][u];
int g=gcd(a,p);a/=g;p/=g;
g=gcd(b,q);b/=g;q/=g;
if (a==b&&p==q) {printf("-1\n");continue;}
if (a*1.0/p>b*1.0/q) swap(a,b),swap(p,q);
likegcd(a,p,b,q,u,v);
printf("%d %d\n",u,v);
}
if (opt==8) {
scanf("%d",&x);
tr.makeroot(root);
tr.access(x);
printf("%d\n",tr.siz[0][x]+1);
}
}
}