BZOJ 1036 树的统计

Posted on 2016-02-13 12:25  ziliuziliu  阅读(244)  评论(0编辑  收藏  举报

这个故事告诉我们数组开小了真的要命。

树剖模板题。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxv 80005
#define maxn 3000005
using namespace std;
long long w[maxv],fath[maxv],top[maxv],son[maxv],size[maxv],dis[maxv];
long long tot=0,lson[maxn],rson[maxn],v1[maxn],v2[maxn],cnt=0;
long long nume=0,n,a,b,q,g[maxv],c[maxv],root;
char type[10];
struct edge
{
long long v,nxt;
}e[maxv];
void addedge(long long u,long long v)
{
e[++nume].v=v;
e[nume].nxt=g[u];
g[u]=nume;
}
void dfs1(long long x)
{
size[x]=1;son[x]=0;
for (long long i=g[x];i;i=e[i].nxt)
{
long long v=e[i].v;
if (v!=fath[x])
{
dis[v]=dis[x]+1;
fath[v]=x;
dfs1(v);
if (size[son[x]]<size[v])
son[x]=v;
size[x]=size[x]+size[v];
}
}
}
void dfs2(long long x,long long fa)
{
w[x]=++tot;top[x]=fa;
if (son[x]!=0)
dfs2(son[x],fa);
for (long long i=g[x];i;i=e[i].nxt)
{
long long v=e[i].v;
if ((v!=fath[x]) && (v!=son[x]))
dfs2(v,v);
}
}
long long build(long long left,long long right)
{
long long now=++cnt;
if (left==right)
return now;
long long mid=(left+right)>>1;
lson[now]=build(left,mid);
rson[now]=build(mid+1,right);
v1[now]=0;
v2[now]=0;
return now;
}
void single_modify(long long now,long long left,long long right,long long pos,long long x)
{
if (left==right)
{
v1[now]=x;
v2[now]=x;
return;
}
else
{
long long mid=(left+right)>>1;
if (pos<=mid)
single_modify(lson[now],left,mid,pos,x);
else single_modify(rson[now],mid+1,right,pos,x);
v1[now]=v1[lson[now]]+v1[rson[now]];
v2[now]=max(v2[lson[now]],v2[rson[now]]);
return;
}
}
long long ask1(long long now,long long left,long long right,long long l,long long r)
{
if ((left==l) && (right==r))
return v1[now];
long long mid=(left+right)>>1;
if (r<=mid) return ask1(lson[now],left,mid,l,r);
else if (l>=mid+1) return ask1(rson[now],mid+1,right,l,r);
else return ask1(lson[now],left,mid,l,mid)+ask1(rson[now],mid+1,right,mid+1,r);
}
long long ask2(long long now,long long left,long long right,long long l,long long r)
{
if ((left==l) && (right==r))
return v2[now];
long long mid=(left+right)>>1;
if (r<=mid) return ask2(lson[now],left,mid,l,r);
else if (l>=mid+1) return ask2(rson[now],mid+1,right,l,r);
else return max(ask2(lson[now],left,mid,l,mid),ask2(rson[now],mid+1,right,mid+1,r));
}
void work()
{
scanf("%s",type);
if (type[0]=='C')
{
scanf("%lld%lld",&a,&b);
single_modify(root,1,tot,w[a],b);
c[a]=b;
}
else if (type[1]=='M')
{
scanf("%lld%lld",&a,&b);
if (a==b) {printf("%lld\n",c[a]);return;}
long long f1,f2,ans=-10000000000;
f1=top[a];f2=top[b];
while (f1!=f2)
{
if (dis[f1]<dis[f2])
{
swap(f1,f2);
swap(a,b);
}
ans=max(ans,ask2(root,1,tot,w[f1],w[a]));
a=fath[f1];f1=top[a];
}
if (a!=b)
{
if (dis[a]>dis[b])
swap(a,b);
ans=max(ans,ask2(root,1,tot,w[a],w[b]));
}
printf("%lld\n",max(ans,c[b]));
}
else
{
scanf("%lld%lld",&a,&b);
if (a==b) {printf("%lld\n",c[a]);return;}
long long f1,f2,ans=0;
f1=top[a];f2=top[b];
while (f1!=f2)
{
if (dis[f1]<dis[f2])
{
swap(f1,f2);
swap(a,b);
}
ans=ans+ask1(root,1,tot,w[f1],w[a]);
a=fath[f1];f1=top[a];
}
if (a!=b)
{
if (dis[a]>dis[b])
swap(a,b);
ans=ans+ask1(root,1,tot,w[son[a]],w[b]);
}
printf("%lld\n",ans+c[a]);
}
return;
}
int main()
{
memset(g,0,sizeof(g));
memset(size,0,sizeof(size));
scanf("%lld",&n);
for (long long i=1;i<=n-1;i++)
{
scanf("%lld%lld",&a,&b);
addedge(a,b);
addedge(b,a);
}
for (long long i=1;i<=n;i++)
scanf("%lld",&c[i]);
dis[1]=0;
dfs1(1);
dfs2(1,1);
root=build(1,tot);
for (long long i=1;i<=n;i++)
single_modify(root,1,tot,w[i],c[i]);
scanf("%lld",&q);
for (long long i=1;i<=q;i++)
work();
return 0;
}