标签:树链剖分
开学就被送去开学考
寒假一点文化课都没搞你还考个毛(╯‵□′)╯︵┻━┻
最后果然还是挂了(不过至少还没出班里前十= =)
回机房第一天想了想决定再去写一个沙茶链剖
(P.S.交这个题时候BZOJ挂了,但是Codevs是可以过的而且去COGS测了一遍也没问题所以BZOJ应该也能过哪天想起来再去BZOJ测一遍)
题目描述 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 Description
输入文件的第一行为一个整数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 Description
对于每个“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 Size & Hint
对于100%的数据,保证1
想不到当年的浙江省选也会出裸题233
代码奇丑无比,不但长而且速度也比较慢(反正能AC就不管那么多了╮(╯▽╰)╭)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXINT 0x7fffffff
#define MAXN 100010
#define lchild rt<<1,l,mid
#define rchild rt<<1|1,mid+1,r
#define ln rt<<1
#define rn rt<<1|1
using namespace std;
int w[MAXN];
int size[MAXN],deep[MAXN],chain[MAXN],num[MAXN],fa[MAXN][18];
bool vis[MAXN];
int top,tp;
int a,b;
int u,v;
int n,q;
char ch[6];
struct edge
{
edge *next;
int to;
}*prev[MAXN],e[MAXN*2];
struct seg
{
int maxn;
int sum;
int l;
int r;
}tree[MAXN*4];
void insert(int u,int v)
{
e[++top].to=v;
e[top].next=prev[u];
prev[u]=&e[top];
}
void dfs1(int x)
{
size[x]=1;
vis[x]=1;
for (int i=1;i<=17;i++)
{
if (deep[x]<(1<<i)) break;
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for (edge *i=prev[x];i;i=i->next)
{
int t=i->to;
if (vis[t]) continue;
deep[t]=deep[x]+1;
fa[t][0]=x;
dfs1(t);
size[x]+=size[t];
}
}
void dfs2(int x,int last)
{
chain[x]=last;
num[x]=++tp;
int t=0;
for (edge *i=prev[x];i;i=i->next)
if (deep[i->to]>deep[x]&&size[t]<size[i->to])
t=i->to;
if (!t) return;
dfs2(t,last);
for (edge *i=prev[x];i;i=i->next)
if (deep[i->to]>deep[x]&&i->to!=t)
dfs2(i->to,i->to);
}
void build(int rt=1,int l=1,int r=n)
{
tree[rt].l=l;
tree[rt].r=r;
if (l==r) return;
int mid=(l+r)>>1;
build(lchild);
build(rchild);
}
int lca(int a,int b)
{
if (deep[a]<deep[b]) swap(a,b);
int t=deep[a]-deep[b];
for (int i=0;i<=17;i++)
if (t&(1<<i)) a=fa[a][i];
for (int i=17;i>=0;i--)
if (fa[a][i]!=fa[b][i])
{
a=fa[a][i];
b=fa[b][i];
}
if (a==b) return a;
else return fa[a][0];
}
void modify(int rt,int x,int nu)
{
int L=tree[rt].l,R=tree[rt].r;
int mid=(L+R)>>1;
if (L==R)
{
tree[rt].maxn=tree[rt].sum=nu;
return;
}
if (x<=mid) modify(ln,x,nu);
else
if (x>mid) modify(rn,x,nu);
tree[rt].maxn=max(tree[ln].maxn,tree[rn].maxn);
tree[rt].sum=tree[ln].sum+tree[rn].sum;
}
int query_sum(int rt,int l,int r)
{
int L=tree[rt].l,R=tree[rt].r,mid=(L+R)>>1;
if (L==l&&R==r)
{
return tree[rt].sum;
}
if (l>mid) return query_sum(rn,l,r);
else
if (r<=mid) return query_sum(ln,l,r);
else
return query_sum(lchild)+query_sum(rchild);
}
int query_max(int rt,int l,int r)
{
int L=tree[rt].l,R=tree[rt].r,mid=(L+R)>>1;
if (L==l&&R==r)
{
return tree[rt].maxn;
}
if (l>mid) return query_max(rn,l,r);
else
if (r<=mid) return query_max(ln,l,r);
else
return max(query_max(lchild),query_max(rchild));
}
int Query_sum(int a,int b)
{
int ret=0;
while (chain[a]!=chain[b])
{
ret+=query_sum(1,num[chain[a]],num[a]);
a=fa[chain[a]][0];
}
ret+=query_sum(1,num[b],num[a]);
return ret;
}
int Query_max(int a,int b)
{
int ret=-MAXINT;
while (chain[a]!=chain[b])
{
ret=max(ret,query_max(1,num[chain[a]],num[a]));
a=fa[chain[a]][0];
}
ret=max(ret,query_max(1,num[b],num[a]));
return ret;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
insert(u,v);
insert(v,u);
}
for (int i=1;i<=n;i++)
scanf("%d",&w[i]);
scanf("%d",&q);
dfs1(1);
dfs2(1,1);
build();
for (int i=1;i<=n;i++)
modify(1,num[i],w[i]);
while (q--)
{
scanf("%s",ch);
if (ch[1]==‘H‘)
{
scanf("%d%d",&a,&b);
w[a]=b;
modify(1,num[a],b);
}
else
if (ch[1]==‘M‘)
{
scanf("%d%d",&a,&b);
int t=lca(a,b);
printf("%d\n",max(Query_max(a,t),Query_max(b,t)));
}
else
if (ch[1]==‘S‘)
{
scanf("%d%d",&a,&b);
int t=lca(a,b);
printf("%d\n",Query_sum(a,t)+Query_sum(b,t)-w[t]);
}
}
}
标签:树链剖分
原文地址:http://blog.csdn.net/creationaugust/article/details/44202759