11
8
2015
0

[BZOJ1036] [ZJOI2008] 树的统计Count

这是一个坑……得过一阵子再填……

NOIP爆炸了心情不好……

现在打算填坑了。

这题是一个树链剖分,据说LCT也行。但是蒟蒻我啥也不会,于是强行学了一个晚上的树链剖分,总算A掉了这题。

我觉得网上题解已经烂大街了……所以就不发题解了,只(懒)放(癌)代(发)码(作)。

树链剖分+线段树

#include<cstdio>
#include<algorithm>
using namespace std;

int n,w[30005],dep[30005],h[30005],en,data[30005],Q,id[30005],siz[30005],fa[30005],son[30005],top[30005],pre[30005],segn;
char ask[10];

struct Edge{
int b,next;
}e[60005];

struct SegTree{
int l,r,v,sum;
}tr[120005];

void add(int sa,int sb){
e[++en].b=sb;
e[en].next=h[sa];
h[sa]=en;
}

void dfs1(int u,int father,int deep){
dep[u]=deep;
fa[u]=father;
son[u]=0;
siz[u]=1;
//printf("ZZT:%d %d %d\n",u,father,deep);
for(int i=h[u];i;i=e[i].next){
    int v=e[i].b;
    if(v==father)continue;
    dfs1(v,u,deep+1);
    siz[u]+=siz[v];
    if(siz[v]>siz[son[u]]){
        son[u]=v;
    }
}
}

void dfs2(int u,int ux){
top[u]=ux;
id[u]=++segn;
pre[segn]=u;
if(son[u])dfs2(son[u],ux);
else return;
//printf("Tr:%d %d\n",u,ux);
for(int i=h[u];i;i=e[i].next){
    int v=e[i].b;
    if(v==fa[u] || v==son[u])continue;
    dfs2(v,v);
}
}

void Build(int root,int l,int r){
tr[root].l=l;
tr[root].r=r;
if(l==r){
    tr[root].v=data[pre[l]];
    tr[root].sum=data[pre[l]];
    return;
}
int mid=(l+r)/2;
Build(root*2,l,mid);
Build(root*2+1,mid+1,r);
tr[root].v=max(tr[root*2].v,tr[root*2+1].v);
tr[root].sum=tr[root*2].sum+tr[root*2+1].sum;
}

void Update(int root,int pos,int val){
if(tr[root].l==tr[root].r){
    tr[root].v+=val;
    tr[root].sum+=val;
    //printf("Tx:%d %d %d\n",root,tr[root].v,tr[root].sum);
    return;
}
int mid=(tr[root].l+tr[root].r)/2;
if(pos<=mid)Update(root*2,pos,val);
if(pos>=mid+1)Update(root*2+1,pos,val);
tr[root].sum=tr[root*2].sum+tr[root*2+1].sum;
tr[root].v=max(tr[root*2].v,tr[root*2+1].v);
}

int QuerySum(int root,int l,int r){
if(tr[root].l>=l && tr[root].r<=r){
    return tr[root].sum;
}
int mid=(tr[root].l+tr[root].r)/2;
int ans=0;
if(l<=mid)ans+=QuerySum(root*2,l,r);
if(r>=mid+1)ans+=QuerySum(root*2+1,l,r);
return ans;
}

int QueryMax(int root,int l,int r){
if(tr[root].l>=l && tr[root].r<=r){
    return tr[root].v;
}
int mid=(tr[root].l+tr[root].r)/2;
int ans=-2147483647;
if(l<=mid)ans=max(ans,QueryMax(root*2,l,r));
if(r>=mid+1)ans=max(ans,QueryMax(root*2+1,l,r));
return ans;
}

int AskSum(int u,int v){
int f1=top[u],f2=top[v],ans=0;
while(f1!=f2){
    if(dep[f1]<dep[f2]){
        swap(f1,f2);
        swap(u,v);
    }
    ans+=QuerySum(1,id[f1],id[u]);
    u=fa[f1];
    f1=top[u];
}
if(dep[u]>dep[v]){
    swap(u,v);
}
ans+=QuerySum(1,id[u],id[v]);
return ans;
}

int AskMax(int u,int v){
int f1=top[u],f2=top[v],ans=-2147483647;
while(f1!=f2){
    if(dep[f1]<dep[f2]){
        swap(f1,f2);
        swap(u,v);
    }
    ans=max(ans,QueryMax(1,id[f1],id[u]));
    u=fa[f1];
    f1=top[u];
}
if(dep[u]>dep[v]){
    swap(u,v);
}
ans=max(ans,QueryMax(1,id[u],id[v]));
return ans;
}

int main(){
freopen("1036.in","r",stdin);
freopen("1036.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<n;i++){
    int sa,sb;
    scanf("%d %d",&sa,&sb);
    add(sa,sb);
    add(sb,sa);
}
for(int i=1;i<=n;i++){
    scanf("%d",&data[i]);
}
dfs1(1,0,1);
dfs2(1,1);
Build(1,1,n);
scanf("%d",&Q);
while(Q--){
    int sa,sb;
    scanf("%s %d %d",&ask,&sa,&sb);
    if(ask[0]=='C'){
        Update(1,id[sa],sb-data[sa]);
        data[sa]=sb;
    }
    if(ask[0]=='Q'){
        if(ask[1]=='S'){
            printf("%d\n",AskSum(sa,sb));
        }
        if(ask[1]=='M'){
            printf("%d\n",AskMax(sa,sb));
        }
    }
}
return 0;
}

树链剖分+树状数组(正在填坑中……)

LCT(正在填坑中……)

Category: BZOJ | Tags: bzoj | Read Count: 610

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com