【SDOI2014】旅行

Description

【SDOI2014】旅行_第1张图片

Solution

用什么

很明显,这是一个树上操作,但是需要类似线段树的维护,一个很裸的树链剖分加线段树。

怎么做

因为有c个宗教,那么就开c棵线段树。然后就可以了。

空间太大了

我用了动态开空间,类似主席树那样打。在线大法好!
也可以打一个离散化。离线大法好!

Code

#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100007;
int i,j,k,l,n,m,ans;
int first[maxn*2],next[maxn*2],last[maxn*2],a[maxn],b[maxn],num,tot;
int size[maxn],fa[maxn],deep[maxn],son[maxn],w[maxn],sum;
int root[maxn],top[maxn];
bool bz[maxn];
char s[5];
struct node{
    int l,r,sum,da;
}t[maxn*50]; 
void add(int x,int y){
    last[++num]=y;
    next[num]=first[x];
    first[x]=num;
    last[++num]=x;
    next[num]=first[y];
    first[y]=num;
}
void dfs1(int x,int y){
    int i,j=0,k=0;
    size[x]=1;
    for(i=first[x];i;i=next[i]){
        if(last[i]!=y){
            fa[last[i]]=x;
            deep[last[i]]=deep[x]+1;
            dfs1(last[i],x);
            size[x]+=size[last[i]]; 
            if(klast[i]]){
                k=size[last[i]];
                son[x]=last[i];
            }
        }
    }
}
void dfs2(int x,int y){
    top[x]=y;
    w[x]=++tot;
    if(!son[x]) return;
    dfs2(son[x],y);
    for(int i=first[x];i;i=next[i]){
        if(last[i]!=fa[x]&&last[i]!=son[x]){
            dfs2(last[i],last[i]);
        }
    }
}
void change(int &x,int l,int r,int y,int z){
    if(x==0)x=++sum;
    if(l==r){t[x].da=t[x].sum=z;return;}
    int mid=(l+r)/2;
    if(y<=mid)change(t[x].l,l,mid,y,z);
    else change(t[x].r,mid+1,r,y,z);
    t[x].sum=t[t[x].l].sum+t[t[x].r].sum;
    t[x].da=max(t[t[x].l].da,t[t[x].r].da);
} 
int findsum(int x,int l,int r,int y,int z){
    if(x==0)return 0;
    if(y>z)return 0;
    if(l==y&&r==z){
        return t[x].sum;
    }
    else{
        int mid=(l+r)/2;
        if(z<=mid)return findsum(t[x].l,l,mid,y,z);
        else if(y>mid)return findsum(t[x].r,mid+1,r,y,z);
        else{
            return findsum(t[x].l,l,mid,y,mid)+findsum(t[x].r,mid+1,r,mid+1,z);
        }
    } 
}
int findda(int x,int l,int r,int y,int z){
    if(x==0)return 0;
    if(y>z)return 0;
    if(l==y&&r==z){
        return t[x].da;
    }
    else{
        int mid=(l+r)/2;
        if(z<=mid)return findda(t[x].l,l,mid,y,z);
        else if(y>mid)return findda(t[x].r,mid+1,r,y,z);
        else{
            return max(findda(t[x].l,l,mid,y,mid),findda(t[x].r,mid+1,r,mid+1,z));
        }
    } 
}
int zhaoda(int x,int y,int z){
    int f1=top[x],f2=top[y],o=-0x7fffffff;
    while(f1!=f2){
        if(deep[f1]x,y);
            swap(f1,f2);
        }
        o=max(o,findda(root[z],1,n,w[f1],w[x]));
        x=fa[f1];f1=top[x];
    }
    if(deep[x]y])swap(x,y);
    return o=max(o,findda(root[z],1,n,w[y],w[x]));
} 
int zhaosum(int x,int y,int z){
    int f1=top[x],f2=top[y],o=0;
    while(f1!=f2){
        if(deep[f1]x,y);
        }
        o+=findsum(root[z],1,n,w[f1],w[x]);
        x=fa[f1];f1=top[x];
    }
    if(deep[x]y])swap(x,y);
    return o+=findsum(root[z],1,n,w[y],w[x]);
}  
int main(){
//  freopen("travel.in","r",stdin);
//  freopen("travel.out","w",stdout);
    scanf("%d%d",&n,&m);
    fo(i,1,n){
        scanf("%d%d",&a[i],&b[i]);
    }
    fo(i,1,n-1){
        scanf("%d%d",&k,&l);
        add(k,l);
    }
    deep[1]=1;
    dfs1(1,0);
    dfs2(1,1);
    fo(i,1,n){
        change(root[b[i]],1,n,w[i],a[i]);
    }
    fo(i,1,m){
        scanf("%s%d%d",s+1,&k,&l);
        if(s[1]=='C'){
            if(s[2]=='C'){
                change(root[b[k]],1,n,w[k],0);
                b[k]=l;
                change(root[b[k]],1,n,w[k],a[k]);
            }
            else{
                a[k]=l;
                change(root[b[k]],1,n,w[k],l);
            }
        }
        else{
            if(s[2]=='S'){
                ans=zhaosum(k,l,b[k]);
                printf("%d\n",ans);
            }
            else{
                ans=zhaoda(k,l,b[k]);
                printf("%d\n",ans);
            }
            if(ans==8469){
                int opp=1;
            }
        }
    }
}

你可能感兴趣的:(树链剖分,线段树,离线大法,省选,可持久化线段树)