码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ1036 树的统计Count

时间:2015-02-28 11:29:41      阅读:149      评论:0      收藏:0      [点我收藏+]

标签:树链剖分   线段树   

题目

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


代码

感谢wfwbz的指导

#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cstdio>
#include<vector>
#define R0(i,n) for(register int i=0;i<n;++i)
#define R1(i,n) for(register int i=1;i<=n;++i)
#define cl(x,c) memset(x,c,sizeof x)
#define INF 0x3f3f3f3f
#define mn 30010

using namespace std;
typedef long long ll;
template <class T> inline void read(T&x){
    bool f = false; char ch;
    for (ch = getchar(); ch <= 32; ch = getchar());
    if (ch == ‘-‘) f = true, ch = getchar();
    for (x = 0; ch > 32; ch = getchar()) x = x * 10 + ch - ‘0‘;
    if (f) x = -x;
}
template <class T> inline void write(T x){
    if (x < 0) putchar(‘-‘), x = -x;
    if (x < 10)
        putchar(x + ‘0‘);
    else
        write(x / 10), putchar(x % 10 + ‘0‘);
}
template <class T> inline void writeln(T x){
    write(x);puts("");
}
void setIO(string t){
string a=t+".in",b=t+".out";
freopen(a.c_str(),"r",stdin);
freopen(b.c_str(),"w",stdout);
}
//数据
int _[mn],__[mn],n,m; 

//线段树
#define lc      k<<1
#define rc      k<<1|1
#define M       ((l+r)>>1)
#define All     1,1,n
#define lson lc,l,M
#define rson rc,M+1,r

int sumv[mn<<2], maxv[mn<<2];

void push_up(int k){
    sumv[k] = sumv[lc] + sumv[rc];
    maxv[k] = max(maxv[lc], maxv[rc]);
}

void build(int k,int l,int r){
    if(l==r)sumv[k]=maxv[k]=__[l];
    else build(lson),build(rson),push_up(k);
}

int _l, _r,_a,_b;//全局变量减少传的参数 
int query_sum(int k,int l,int r){
    if(_l<=l&&r<=_r)return sumv[k];
    int ret = 0;
    if(_l<=M)ret+=query_sum(lson);
    if(M<_r) ret+=query_sum(rson);
    return ret;
}
int query_max(int k,int l,int r){
    if(_l<=l&&r<=_r)return maxv[k];
    int ret=-INF;
    if(_l<=M) ret=max(ret,query_max(lson));
    if(M <_r) ret=max(ret,query_max(rson));
    return ret;
}
void update(int k,int l,int r) {
    if(l==_a &&r==_a)sumv[k]=maxv[k]=_b;
    else {
        if(_a<=M) update(lson);
        else update(rson);
        push_up(k);
    }
}



//重链剖分
int dep[mn],fa[mn],size[mn],tid[mn],top[mn],son[mn];
/*
dep深度
fa父亲节点
size以i为根的子树节点个数
tid新编号
top祖先
son孩子节点
这一块还不太明白如果有错欢迎指正
*/
 vector<int>ch[mn];
void f_h_e(int x,int father,int depth){//找重边
    dep[x]=depth,fa[x]=father,size[x]=1;
    int maxsize=0;
    R0(i,ch[x].size()){
        int child=ch[x][i];
        if(child!=father){
            f_h_e(child,x,depth+1);
            size[x]+=size[child];
            if(size[child]>maxsize)maxsize=size[child],son[x]=child;
        }
    }
} 
int label;//新编号用

void c_h_e(int x,int anc){//连重链
    __[tid[x]=++label]=_[x];//按新编号排列数据
    top[x]=anc;//top 重链祖先
    if(son[x]){
        c_h_e(son[x],anc);
        R0(i,ch[x].size()){
            int child=ch[x][i];
            if(child!=fa[x]&&child!=son[x])c_h_e(child,child);//轻的自己连自己 
        }
    } 
}


//修改 
//单点修改直接走数据结构

//询问
int ask_sum(int x,int y){
    int ret=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        _l=tid[top[x]],_r=tid[x],ret+=query_sum(All);
        x=fa[top[x]];
    }//不在同一条重链上
    if(dep[x]>dep[y])swap(x,y);
    _l=tid[x],_r=tid[y],ret+=query_sum(All);
    return ret;//到达同一条重链
} 
int ask_max(int x,int y){
    int ret=-INF;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        _l=tid[top[x]],_r=tid[x],ret=max(ret,query_max(All));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    _l=tid[x],_r=tid[y],ret=max(ret,query_max(All));
    return ret;
} //同上

int main(){
    read(n);int a,b;
    R1(i,n-1){
        read(a),read(b);
        ch[a].push_back(b);
        ch[b].push_back(a);
    }
    R1(i,n)read(_[i]);

    //
    cl(maxv,-0x3f);
    f_h_e(1,1,1);
    c_h_e(1,1);
    build(All);
    read(m);
    char cmd[7];
    R0(i,m){
        scanf("%s",cmd);
        read(a),read(b);
        switch(cmd[1]){
            case‘S‘:{writeln(ask_sum(a,b));break;}
            case‘M‘:{writeln(ask_max(a,b));break;}
            case‘H‘:{_a=tid[a],_b=b;update(All);break;}//这里_a要用新标号
        }
    }
    return 0;
}

BZOJ1036 树的统计Count

标签:树链剖分   线段树   

原文地址:http://blog.csdn.net/iostream0/article/details/43983119

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!