bzoj 1036 //1036: [ZJOI2008]树的统计Count 树链剖分

bzoj 1036   //1036: [ZJOI2008]树的统计Count   树链剖分

bzoj 1036   //1036: [ZJOI2008]树的统计Count   //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1036

更多题解,详见https://blog.csdn.net/mrcrack/article/details/90228694BZOJ刷题记录

1036 Accepted 5560 kb 3208 ms C++/Edit 3362 B

//1036: [ZJOI2008]树的统计Count
//在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=1036
//n=30000,w=30000,n*w=9*10^8 int不会溢出。
//采用树链剖分算法,若不清楚,详见https://blog.csdn.net/mrcrack/article/details/102884839
//树链剖分算法,遇到段错误,算是常事了。
//反复排查,linux在main函数内不好排查段错误,必须深入到具体函数内部去,增加了不少工作量。
/*
a[k].l=a[k].r=l,a[k].mx=a[k].sum=v[rk[l]];//此处错写成a[k].l=a[k].r,a[k].mx=a[k].sum=v[rk[l]];查了2个小时.2019-11-3 20:39
一处不起眼的错误啊。
*/
//样例通过,提交AC.2019-11-3 20:43   收获,对线段树节点的改、查,理解更深刻了。
#include
#include
#define lson k<<1
#define rson k<<1|1
#define maxn 30100
struct node1{
    int to,next;
}e[maxn<<1];
struct node2{
    int l,r,sum,mx;
}a[maxn<<2];
int v[maxn],n,head[maxn],R=1,d[maxn],fa[maxn],size[maxn],son[maxn],id[maxn],rk[maxn],cnt,top[maxn];
int max(int a,int b){
    return a>b?a:b;
}
void add_edge(int u,int v){
    cnt++,e[cnt].to=v,e[cnt].next=head[u],head[u]=cnt;
}
void dfs1(int x){
    int v,b;
    d[x]=d[fa[x]]+1,size[x]=1;
    for(b=head[x];b;b=e[b].next){
        v=e[b].to;
        if(v!=fa[x]){
            fa[v]=x,dfs1(v),size[x]+=size[v];
            if(size[son[x]]         }
    }
}
void dfs2(int x,int tp){
    int v,b;
    top[x]=tp,cnt++,rk[cnt]=x,id[x]=cnt;
    if(son[x])dfs2(son[x],tp);
    for(b=head[x];b;b=e[b].next){
        v=e[b].to;
        if(v!=fa[x]&&v!=son[x])dfs2(v,v);
    }
}
void pushup(int k){
    a[k].sum=a[lson].sum+a[rson].sum;
    a[k].mx=max(a[lson].mx,a[rson].mx);
}
void update(int l,int r,int c,int k){
    int mid=(a[k].l+a[k].r)/2;
    if(l<=a[k].l&&a[k].r<=r){
        a[k].sum=a[k].mx=c;
        return;
    }
    if(l<=mid)update(l,r,c,lson);
    if(mid+1<=r)update(l,r,c,rson);
    pushup(k);
}
int qmax(int l,int r,int k){
    int mid=(a[k].l+a[k].r)/2,ret=-30100;//此处错写成int mid=(a[k].l+a[k].r)/2,ret=-1;
    if(l<=a[k].l&&a[k].r<=r){
        return a[k].mx;
    }
    if(l<=mid)ret=max(ret,qmax(l,r,lson));
    if(mid+1<=r)ret=max(ret,qmax(l,r,rson));
    return ret;
}
void swap(int *a,int *b){
    int t;
    t=*a,*a=*b,*b=t;
}
int qmaxs(int x,int y,int k){
    int ret=-30100;//此处错写成int ret=-1;
    while(top[x]!=top[y]){
        if(d[top[x]]         ret=max(ret,qmax(id[top[x]],id[x],1)),x=fa[top[x]];
    }
    if(id[x]>id[y])swap(&x,&y);
    ret=max(ret,qmax(id[x],id[y],1));//此处错写成ret=(ret,qmax(id[x],id[y],1));
    return ret;
}
int qsum(int l,int r,int k){
    int mid=(a[k].l+a[k].r)/2,ret=0;
    if(l<=a[k].l&&a[k].r<=r){
        return a[k].sum;
    }
    if(l<=mid)ret+=qsum(l,r,lson);
    if(mid+1<=r)ret+=qsum(l,r,rson);
    return ret;
}
int qsums(int x,int y,int k){
    int ret=0;
    while(top[x]!=top[y]){
        if(d[top[x]]         ret+=qsum(id[top[x]],id[x],1),x=fa[top[x]];
    }
    if(id[x]>id[y])swap(&x,&y);
    ret+=qsum(id[x],id[y],1);
    return ret;
}
void build(int l,int r,int k){
    int mid=(l+r)/2;
    if(l==r){
        a[k].l=a[k].r=l,a[k].mx=a[k].sum=v[rk[l]];//此处错写成a[k].l=a[k].r,a[k].mx=a[k].sum=v[rk[l]];查了2个小时.2019-11-3 20:39
        return;
    }
    build(l,mid,lson);
    build(mid+1,r,rson);
    a[k].l=l,a[k].r=r,pushup(k);
}
int main(){
    int i,a,b,q;
    char cmd[10];
    scanf("%d",&n),memset(head,0,sizeof(head)),cnt=0;
    for(i=1;i     for(i=1;i<=n;i++)scanf("%d",&v[i]);
    memset(son,0,sizeof(son)),fa[R]=0,d[0]=0,dfs1(R);
    cnt=0,dfs2(R,R);
    build(1,n,1);
    scanf("%d",&q);
    while(q--){
        scanf("%s",cmd);
        if(cmd[1]=='M')scanf("%d%d",&a,&b),printf("%d\n",qmaxs(a,b,1));
        else if(cmd[1]=='S')scanf("%d%d",&a,&b),printf("%d\n",qsums(a,b,1));
        else if(cmd[1]=='H')scanf("%d%d",&a,&b),update(id[a],id[a],b,1);
    }
    return 0;
}

 

 

 

你可能感兴趣的:(跟着大佬学算法)