BZOJ 1036

Problem

一棵树上有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本身

Solution

很裸的树链剖分,我尝试用手写栈代替系统栈,然后手写栈代替stl栈,lca部分要注意.. 容易写挂,主要还是写的太少。毕竟我的第一道树链剖分题,纪念一下!

My code

//Hello. I'm Peter.
#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<cctype>
#include<ctime>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double ld;
//const double pi=acos(-1.0);
//const double eps=1e-9;
#define peter cout<<"i am peter"<<endl
#define input freopen("data.txt","r",stdin)
#define randin srand((unsigned int)time(NULL))
#define INT (0x3f3f3f3f)*2
#define LL (0x3f3f3f3f3f3f3f3f)*2
#define gsize(a) (int)a.size()
#define len(a) (int)strlen(a)
#define slen(s) (int)s.length()
#define clr(a) memset(a,0,sizeof(a))
#define clr_true(a) memset(a,true,sizeof(a))
#define clr_queue(q) while(!q.empty()) q.pop()
#define clr_stack(s) while(!s.empty()) s.pop()
#define rep(i, a, b) for (int i = a; i < b; i++)
#define dep(i, a, b) for (int i = a; i > b; i--)
#define repin(i, a, b) for (int i = a; i <= b; i++)
#define depin(i, a, b) for (int i = a; i >= b; i--)
#define MAXN 30100
#define N
#define M 20
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
class Stack{
public:
    int st[MAXN],num;
    inline void clear(){
        num=0;
    }
    inline void push(int x){
        st[num++]=x;
    }
    inline void pop(){
        num--;
    }
    inline int top(){
        //make sure num is positive
        return st[num-1];
    }
    inline int size(){
        return num;
    }
    inline bool empty(){
        return !num;
    }
}st1,st2;
#define lch (id<<1)
#define rch (id<<1|1)
#define mid ((tree[id].left+tree[id].right)>>1)
int n,numq,val[MAXN],rvto[MAXN];
class Segment_Tree{
public:
    struct Tree{
        int left,right;
        int sum,max;
    }tree[MAXN<<2];
    inline void plant(int id,int l,int r){
        tree[id].left=l,tree[id].right=r;
        if(l==r){
            tree[id].sum=val[rvto[l]];
            tree[id].max=val[rvto[l]];
            return;
        }
        plant(lch,l,mid);
        plant(rch,mid+1,r);
        tree[id].sum=tree[lch].sum+tree[rch].sum;
        tree[id].max=max(tree[lch].max,tree[rch].max);
    }
    inline void update(int id,int pos,int v){
        if(tree[id].left==pos&&tree[id].right==pos){
            tree[id].sum=v;
            tree[id].max=v;
            return;
        }
        if(pos<=mid) update(lch,pos,v);
        else update(rch,pos,v);
        tree[id].sum=tree[lch].sum+tree[rch].sum;
        tree[id].max=max(tree[lch].max,tree[rch].max);
    }
    inline int query_sum(int id,int l,int r){
        if(tree[id].left==l&&tree[id].right==r){
            return tree[id].sum;
        }
        if(r<=mid) return query_sum(lch,l,r);
        else if(mid<l) return query_sum(rch,l,r);
        else return query_sum(lch,l,mid)+query_sum(rch,mid+1,r);
    }
    inline int query_max(int id,int l,int r){
        if(tree[id].left==l&&tree[id].right==r){
            return tree[id].max;
        }
        if(r<=mid) return query_max(lch,l,r);
        else if(mid<l) return query_max(rch,l,r);
        else return max(query_max(lch,l,mid),query_max(rch,mid+1,r));
    }
}segtree;
char s[20];
struct Edge{
    int next,from,to;
    bool heavy;
}edge[MAXN<<1];
int head[MAXN],num_edge;
inline void add_Edge(int from,int to){
    int t=++num_edge;
    edge[t].from=from;
    edge[t].to=to;
    edge[t].next=head[from];
    edge[t].heavy=false;
    head[from]=t;
}
int fa[MAXN],dep[MAXN],siz[MAXN],maxidep;
inline void dfs1(){
    st1.clear();
    st2.clear();
    st1.push(1);
    fa[1]=-1;
    dep[1]=0;
    maxidep=0;
    int now,to;
    while(!st1.empty()){
        now=st1.top();
        st1.pop();
        st2.push(now);
        for(int i=head[now];i!=-1;i=edge[i].next){
            to=edge[i].to;
            if(fa[now]==to) continue;
            fa[to]=now;
            dep[to]=dep[now]+1;
            maxidep=max(maxidep,dep[to]);
            st1.push(to);
        }
    }
    while(!st2.empty()){
        now=st2.top();
        st2.pop();
        siz[now]=1;
        int e=-1,maxi=-INT;
        for(int i=head[now];i!=-1;i=edge[i].next){
            to=edge[i].to;
            if(fa[now]==to) continue;
            siz[now]+=siz[to];
            if(siz[to]>maxi){
                maxi=siz[to];
                e=i;
            }
        }
        if(e!=-1) edge[e].heavy=true;
    }
}
int vto[MAXN],dfs_clocks,upto[MAXN];
inline void dfs2(){
    dfs_clocks=0;
    st1.clear();
    int now=1,e=-1,topto=1;
    vto[1]=++dfs_clocks;
    rvto[dfs_clocks]=1;
    upto[1]=1;
    for(int i=head[now];i!=-1;i=edge[i].next){
        if(edge[i].heavy) e=i;
        else st1.push(i);
    }
    if(e!=-1) st1.push(e);
    while(!st1.empty()){
        int ii=st1.top();
        st1.pop();
        now=edge[ii].to;
        vto[now]=++dfs_clocks;
        rvto[dfs_clocks]=now;
        if(!edge[ii].heavy) topto=now;
        upto[now]=topto;
        e=-1;
        for(int i=head[now];i!=-1;i=edge[i].next){
            if(fa[now]==edge[i].to) continue;
            if(edge[i].heavy) e=i;
            else st1.push(i);
        }
        if(e!=-1) st1.push(e);
    }
}
int f[MAXN][M];
inline void lca_init(){
    repin(i,1,n){
        f[i][0]=fa[i];
    }
    for(int j=1;1<<j<=maxidep;j++){
        repin(i,1,n){
            f[i][j]=-1;
            if(f[i][j-1]!=-1) f[i][j]=f[f[i][j-1]][j-1];
        }
    }
}
inline int lca_query(int x,int y){
    if(dep[x]<dep[y]) swap(x,y);
    //make sure dep[x]>=dep[y]
    int j=0;
    for(j=0;1<<j<=dep[x];j++);
    j--;
    for(;j>=0;j--){
        if(f[x][j]!=-1 && dep[f[x][j]]>=dep[y]) x=f[x][j];
    }
    if(x==y) return x;
    for(j=0;1<<j<=dep[x];j++);
    j--;
    for(;j>=0;j--){
        if(f[x][j]!=f[y][j]) x=f[x][j],y=f[y][j];
    }
    return fa[x];
}
inline int jump_max(int x,int aim){
    int res=-INT,from,to;
    while(1){
        from=vto[upto[x]];
        to=vto[x];
        if(from<=vto[aim]){
            res=max(res,segtree.query_max(1,vto[aim],to));
            break;
        }
        res=max(res,segtree.query_max(1,from,to));
        x=fa[upto[x]];
    }
    return res;
}
inline int query_max(int u,int v){
    if(u==v) return segtree.query_max(1,vto[u],vto[v]);
    int lca=lca_query(u,v);
    if(lca==u) return jump_max(v,lca);
    else if(lca==v) return jump_max(u,lca);
    else return max(jump_max(u,lca),jump_max(v,lca));
}
inline int jump_sum(int x,int aim){
    int res=0,from,to;
    while(1){
        from=vto[upto[x]];
        to=vto[x];
        if(from<=vto[aim]){
            res+=segtree.query_sum(1,vto[aim],to);
            break;
        }
        res+=segtree.query_sum(1,from,to);
        x=fa[upto[x]];
    }
    return res;
}
inline int query_sum(int u,int v){
    if(u==v) return segtree.query_sum(1,vto[u],vto[v]);
    int lca=lca_query(u,v);
    if(lca==u) return jump_sum(v,lca);
    else if(lca==v) return jump_sum(u,lca);
    else return jump_sum(u,lca)+jump_sum(v,lca)-segtree.query_sum(1,vto[lca],vto[lca]);
}
int main(){
    n=read();
    repin(i,1,n){
        head[i]=-1;
    }
    num_edge=0;
    repin(i,1,n-1){
        int a,b;
        a=read(),b=read();
        add_Edge(a,b);
        add_Edge(b,a);
    }
    repin(i,1,n){
        val[i]=read();
    }
    dfs1();
    dfs2();
    lca_init();
    segtree.plant(1,1,n);

    numq=read();
    while(numq--){
        scanf("%s",s);
        if(s[0]=='C'){//Change u t
            int u,t;
            u=read(),t=read();
            segtree.update(1,vto[u],t);
        }
        else if(s[1]=='M'){//Qmax u v
            int u,v;
            u=read(),v=read();
            int maxi=query_max(u,v);
            printf("%d\n",maxi);
        }
        else{//Qsum u v
            int u,v;
            u=read(),v=read();
            int sum=query_sum(u,v);
            printf("%d\n",sum);
        }
    }
    return 0;
}

你可能感兴趣的:(数据结构,树链剖分)