bzoj 1036 [ZJOI2008] 树的统计 树链剖分模板题

1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 4465 Solved: 1858
[Submit][Status]
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”的形式给出。 对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。
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

又是找不出错误的时候。。。
参考http://blog.csdn.net/jiangshibiao/article/details/24669751

#include<algorithm>
#include<vector>
#include<cstring>
#include<string>
#include<iomanip>
#include<cstdio>
#include<stack>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<strstream>
using namespace std;
#define sf scanf
#define pf printf
#define mem(a,b) memset(a,b,sizeof(a));
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define MP make_pair
#define mod 998244353
#define ULL unsigned long long
#define LL long long
#define inf 0x3f3f3f3f
#define md ((ll+rr)>>1)
#define ls (i<<1)
#define rs (ls|1)
#define N 5010
#define M 20020


//2017年08月23日08:36:16
int fst[N],nxt[M],to[M],e,val[N],w[N];
int fa[N],dep[N],sz[N],son[N];
int tid[N],top[N];
int sum[N];
bool vis[N];
int label,n;
int mx[N<<2];
void init(){
    mem(fst,-1);
    e=0;
}
void add(int u,int v){
    to[e]=v,nxt[e]=fst[u];fst[u]=e++;
}
void dfs(int u,int p){
    fa[u]=p;
    sz[u]=1;
    for(int i=fst[u];~i;i=nxt[i]){
        int v=to[i];
        if(v==p)continue;
        dep[v]=dep[u]+1;
        dfs(v,u);
        sz[u]+=sz[v];
        if(sz[son[u]]<sz[v]){
            son[u]=sz[v];
        }
    }
}
void dfs2(int u,int t){
    vis[u]=1;
    top[u]=t;
    tid[u]=++label;
    w[label]=val[u];
    if(son[u])dfs2(son[u],t);
        puts("bad");
    for(int i=fst[u];~i;i=nxt[i]){
        int v=to[i];
        puts("bad");
        if(!vis[v])dfs2(v,v);
    }
}
void cut(){
    dep[1]=sz[1]=0;
    mem(son,0);
    dfs(1,-1);
    mem(vis,0);
    label=0;
    dfs2(1,1);
}
void build(int ll,int rr,int i){
    if(ll==rr){
        mx[i]=w[ll]; sum[i]=w[ll];
        return;
    }
    build(ll,md,ls),build(md+1,rr,rs);
    mx[i]=max(mx[ls],mx[rs]);
    sum[i]=sum[ls]+sum[rs];
}
void update(int x,int v,int ll,int rr,int i){
    if(ll==rr){
        sum[i]=v;
        mx[i]=v;return ;
    }
    if(x<=md)update(x,v,ll,md,ls);
    else update(x,v,md+1,rr,rs);
    mx[i]=max(mx[ls],mx[rs]);
    sum[i]=sum[ls]+sum[rs];
}
int qmax(int l,int r,int ll,int rr,int i){
    if(ll==l&&rr==r)return mx[i];
    if(r<=md)
        return qmax(l,r,ll,md,ls);
    if(l>md)
        return qmax(l,r,md+1,rr,rs);
    return max(qmax(l,md,ll,md,ls),qmax(md+1,r,md+1,rr,rs));
}
int qsum(int l,int r,int ll,int rr,int i){
    if(ll==l&&rr==r)return sum[i];
    if(r<=md)
        return qsum(l,r,ll,md,ls);
    if(l>md)
        return qsum(l,r,md+1,rr,rs);
    return qsum(l,md,ll,md,ls)+qsum(md+1,r,md+1,r,rs);
}
int calmax(int x,int y){
    int ret=-inf;
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]])swap(x,y);
        ret=max(ret,qmax(tid[top[y]],tid[y],1,n,1));
        y=fa[top[y]];
    }
    if(x!=y){
        if(dep[x]>dep[y])swap(x,y);
        ret=max(ret,qmax(tid[x]+1,tid[y],1,n,1));
    }
    return ret;
}
int calsum(int x,int y){
    int ret=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]])swap(x,y);
        ret+=(qsum(tid[top[y]],tid[y],1,n,1));
        y=fa[top[y]];
    }
    if(x!=y){
        if(dep[x]>dep[y])swap(x,y);
        ret+=(qsum(tid[top[y]],tid[y],1,n,1));
    }
    return ret;
}
int main(){
    freopen("in.txt","r",stdin);
    sf("%d",&n);
    init();
    for(int i=1;i<=n-1;++i){
        int u,v;sf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    rep(i,1,n)sf("%d",&val[i]);
    cut();
    for(int i=1;i<=n;++i){
        pf("%d ",mx[i]);
    }puts("");
    build(1,n,1);
    int m;sf("%d",&m);
    while(m--){
        char s[10];sf("%s",s);
        if(s[0]=='C'){
            int x,val;sf("%d%d",&x,&val);
            update(x,val,1,n,1);
        }
        else if(s[1]=='S'){
            int u,v;sf("%d%d",&u,&v);
            pf("%d\n",calsum(tid[u],tid[v]));
        }
        else if(s[1]=='M'){
            int u,v;sf("%d%d",&u,&v);
            pf("%d\n",calmax(tid[u],tid[v]));
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值