problem
Description
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身
Input
输入文件的第一行为一个整数n,表示节点的个数。
接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。
接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。
接下来1行,为一个整数q,表示操作的总数。
接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。
Output
对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。
Sample Input
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
Sample Output
4
1
2
2
10
6
5
6
5
16
Data Constraint
Hint
【数据说明】
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
analysis
其实LCT的代码复杂度简直秒杀树剖好伐都说了LCT能做所有树剖题,然而这题连cut操作都没有
-
那不就简单了?
像普通套路一样,询问 x,y x , y 间的路径极值或权值和,就 makeroot(y),access(x),splay(x,0) m a k e r o o t ( y ) , a c c e s s ( x ) , s p l a y ( x , 0 )
然后直接输出 a[x].XXX a [ x ] . X X X 就好了
至于修改 x x 节点的操作,把旋到根,直接修改即可
-
然而WA90
为什么呢?
每次输入的时候,都要把当前节点旋到根,读入后再 update u p d a t e !!!
这样才终于AC了
code
#include<bits/stdc++.h>
#define MAXN 30001
using namespace std;
int t[MAXN][2];
int b[MAXN],fa[MAXN],pf[MAXN],st[MAXN];
char s[10];
int n,m;
struct node
{
int val,sum,mx,size,rev;
}a[MAXN];
int read()
{
int x=0,f=1;
char ch=getchar();
while (ch<'0' || '9'<ch)
{
if (ch=='-')f=-1;
ch=getchar();
}
while ('0'<=ch && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void reverse(int x)
{
if(x)
{
a[x].rev^=1;
swap(t[x][0],t[x][1]);
}
}
void down(int x)
{
if (a[x].rev)
{
reverse(t[x][0]),reverse(t[x][1]);
a[x].rev=0;
}
}
void update(int x)
{
if (x)
{
a[x].size=a[t[x][0]].size+a[t[x][1]].size+1;
a[x].sum=a[x].val+a[t[x][0]].sum+a[t[x][1]].sum;
a[x].mx=max(a[x].val,max(a[t[x][0]].mx,a[t[x][1]].mx));
}
}
void downdata(int x)
{
st[0]=0;
while (x)st[++st[0]]=x,x=fa[x];
while (st[0])down(st[st[0]--]);
}
int lr(int x)
{
return t[fa[x]][1]==x;
}
void rotate(int x)
{
int y=fa[x],k=lr(x);
t[y][k]=t[x][!k];
if (t[x][!k])fa[t[x][!k]]=y;
fa[x]=fa[y];
if (fa[y])t[fa[y]][lr(y)]=x;
t[x][!k]=y;
fa[y]=x,pf[x]=pf[y];
update(y),update(x);
}
void splay(int x, int y)
{
downdata(x);
while (fa[x]!=y)
{
if (fa[fa[x]]!=y)
{
if (lr(x)==lr(fa[x]))rotate(fa[x]);
else rotate(x);
}
rotate(x);
}
}
void access(int x)
{
for (int y=0;x;update(x),y=x,x=pf[x])
{
splay(x,0);
fa[t[x][1]]=0;
pf[t[x][1]]=x;
t[x][1]=y;
fa[y]=x;
pf[y]=0;
}
}
void makeroot(int x)
{
access(x);
splay(x,0);
reverse(x);
}
void link(int x,int y)
{
makeroot(x);
pf[x]=y;
}
int main()
{
n=read();
for (int i=1;i<n;i++)link(read(),read());
a[0].mx=-2147483647,a[0].sum=a[0].val=0;
for (int i=1;i<=n;i++)
{
splay(i,0);
a[i].mx=a[i].sum=a[i].val=read();
update(i);
}
m=read();
while (m--)
{
scanf("%s",&s);
int x=read(),y=read();
if (s[1]=='M')//max
{
makeroot(y);
access(x);
splay(x,0);
printf("%d\n",a[x].mx);
}
else if (s[1]=='S')//sum
{
makeroot(y);
access(x);
splay(x,0);
printf("%d\n",a[x].sum);
}
else //change
{
splay(x,0);
a[x].val=y;
update(x);
}
}
}

本文介绍了一种使用LCT算法解决树上路径查询问题的方法,包括节点权值更改、路径最大权值查询及路径权值和查询等功能。通过具体实例展示了LCT算法相较于树剖分算法的优势。
366

被折叠的 条评论
为什么被折叠?



