题目描述
16~83%
不会
100%
用LCT维护树的形态,access后往上跳来找lca
之后用dfs序+线段树维护权值和
其实正解就是直接用lca随便搞搞
话说我已经变成无(sha)脑(bi)数据结构选手了吗。。。
code
#include <iostream>
#include <cstdlib>
#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 N 300000
using namespace std;
int fa[N+1];
int ch[N+1][2];
bool rev[N+1];
bool isroot[N+1];
long long tr[4*N+1][2];
int a[N+N+1][2];
int ls[N+1];
int w[N+1];
int st[N+1];
int ed[N+1];
int n,Q,i,j,k,l,type,len,root;
long long Find,x,y,z,ans,p;
void New(int x,int y)
{
len++;
a[len][0]=y;
a[len][1]=ls[x];
ls[x]=len;
}
void swap(int &x,int &y)
{
int z=x;
x=y;
y=z;
}
void init(int fa,int t)
{
int i;
st[t]=++j;
for (i=ls[t]; i; i=a[i][1])
if (a[i][0]!=fa)
init(t,a[i][0]);
ed[t]=j;
}
void down(int t)
{
if (rev[t])
{
swap(ch[t][0],ch[t][1]);
rev[ch[t][0]]^=1;
rev[ch[t][1]]^=1;
rev[t]=0;
}
}
void rot(int t)
{
if (isroot[t]) return;
int Fa=fa[t];
int x=(ch[Fa][1]==t);
ch[Fa][x]=ch[t][x^1];
fa[ch[t][x^1]]=Fa;
ch[t][x^1]=Fa;
fa[t]=fa[Fa];
fa[Fa]=t;
isroot[t]=isroot[Fa];
isroot[Fa]=0;
if (!isroot[t])
ch[fa[t]][ch[fa[t]][1]==Fa]=t;
}
void splay(int t)
{
while (!isroot[t])
{
down(fa[fa[t]]);
down(fa[t]);
down(t);
if (isroot[fa[t]])
rot(t);
else
if ((ch[fa[fa[t]]][1]==fa[t]) ^ (ch[fa[t]][1]==t))
rot(t),rot(t);
else
rot(fa[t]),rot(t);
}
}
void access(int t)
{
int x=0;
while (t)
{
splay(t);
down(t);
isroot[ch[t][1]]=1;
isroot[x]=0;
ch[t][1]=x;
x=t;
t=fa[t];
}
}
void moveroot(int t)
{
access(t);
splay(t);
root=t;
rev[t]=1;
down(t);
}
void link(int x,int y)
{
moveroot(y);
fa[y]=x;
}
void Down(int t,int len)
{
tr[t][0]+=tr[t][1]*len;
if (len>1)
{
tr[t*2][1]+=tr[t][1];
tr[t*2+1][1]+=tr[t][1];
}
tr[t][1]=0;
}
void change(int t,int l,int r,int x,int y,int s)
{
int mid=(l+r)/2;
if (x<=l && r<=y)
{
tr[t][1]+=s;
Down(t,r-l+1);
return;
}
Down(t,r-l+1);
if (x<=mid)
change(t*2,l,mid,x,y,s);
if (mid<y)
change(t*2+1,mid+1,r,x,y,s);
Down(t*2,mid-l+1);
Down(t*2+1,r-mid);
tr[t][0]=tr[t*2][0]+tr[t*2+1][0];
}
void find(int t,int l,int r,int x,int y)
{
int mid=(l+r)/2;
Down(t,r-l+1);
if (x<=l && r<=y)
{
Find+=tr[t][0];
return;
}
if (x<=mid)
find(t*2,l,mid,x,y);
if (mid<y)
find(t*2+1,mid+1,r,x,y);
}
bool pd(int x,int y) {return ((st[x]<=st[y]) && (ed[y]<=ed[x]));}
int main()
{
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d%d",&n,&Q);
fo(i,1,n)
{
scanf("%d",&w[i]);
isroot[i]=1;
}
fo(i,2,n)
{
scanf("%d%d",&x,&y);
link(x,y);
New(x,y);
New(y,x);
}
j=0;
init(0,1);
fo(i,1,n)
change(1,1,n,st[i],st[i],w[i]);
moveroot(1);
for (;Q;Q--)
{
scanf("%d",&type);
switch (type)
{
case 1:
{
scanf("%lld",&x);
moveroot(x);
break;
}
case 2:
{
scanf("%lld%lld%lld",&x,&y,&z);
access(x);
i=y;
while (i)
{
p=i;
while (!isroot[i])
i=fa[i];
i=fa[i];
}
if (p==root)
{
tr[1][1]+=z;
Down(1,n);
}
else
if (pd(p,root))
{
int P=p;
tr[1][1]+=z;
Down(1,n);
access(p);
if (!ch[p][0] && !ch[p][1])
p=fa[p];
else
{
if (ch[p][0])
i=0; else i=1;
p=ch[p][i];
down(p);//考试时没加上这个
i^=1;
while (ch[p][i])
{
p=ch[p][i];
down(p);//考试时没加上这个
}
}
change(1,1,n,st[p],ed[p],-z);
}
else
change(1,1,n,st[p],ed[p],z);
break;
}
case 3:
{
moveroot(root);
ans=0;
scanf("%lld",&p);
if (p==root)
{
Down(1,n);
ans=tr[1][0];
}
else
if (pd(p,root))
{
Down(1,n);
ans=tr[1][0];
access(p);
if (!ch[p][0] && !ch[p][1])
p=fa[p];
else
{
if (ch[p][0])
i=0; else i=1;
p=ch[p][i];
down(p);//考试时没加上这个
i^=1;
while (ch[p][i])
{
p=ch[p][i];
down(p);//考试时没加上这个
}
}
Find=0;
find(1,1,n,st[p],ed[p]);
ans-=Find;
}
else
{
Find=0;
find(1,1,n,st[p],ed[p]);
ans=Find;
}
printf("%lld\n",ans);
break;
}
}
}
fclose(stdin);
fclose(stdout);
return 0;
}
后记
考试时因为没下传标记爆掉。。。
没错这是同一个程序
O2真神(sha)奇(bi)