P3313 [SDOI2014]旅行

题目链接(洛谷)

题目链接(bzoj)

题解:

对于每一种宗教都维护一棵线段树,每次在对应的线段树上查询和与最大值即可。修改的话同样如此。剩下便是树剖干的事情。

P3313 [SDOI2014]旅行
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
struct node{
    int nxt,to;
}edge[maxn*2];
int head[maxn];
int n,q;
int x,y;
struct node1{
    int rc,lc;
    long long maxx,sum;
}tree[maxn*21];
int root[maxn];
int faith[maxn];
int level[maxn];
char opt[666];
int cnt;
void add(int x,int y){
    edge[++cnt].nxt=head[x];
    edge[cnt].to=y;
    head[x]=cnt;
}
int dep[maxn],fa[maxn],siz[maxn],son[maxn];
void dfs1(int x,int f){
    dep[x]=dep[f]+1;
    fa[x]=f;
    siz[x]=1;
    int maxson=-1;
    for(register int i=head[x];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==fa[x]) continue;
        dfs1(v,x);
        siz[x]+=siz[v];
        if(siz[v]>maxson){
            maxson=siz[v];
            son[x]=v;
        }
    }
}
int top[maxn],id[maxn],in;
void dfs2(int x,int topf){
    top[x]=topf;
    id[x]=++in;
    if(!son[x]) return;
    dfs2(son[x],topf);
    for(register int i=head[x];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==fa[x]||v==son[x]) continue;
        dfs2(v,v);
    }
}
int tot;
void build(int &rt,int l,int r,int v,int pos){
    if(!rt) rt=++tot;
    if(l==pos&&pos==r){
        tree[rt].maxx=v;
        tree[rt].sum=v;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) build(tree[rt].lc,l,mid,v,pos);
    else build(tree[rt].rc,mid+1,r,v,pos);
    tree[rt].maxx=max(tree[tree[rt].lc].maxx,tree[tree[rt].rc].maxx);
    tree[rt].sum=tree[tree[rt].lc].sum+tree[tree[rt].rc].sum;
}
void clear(int rt){
    tree[rt].lc=0;
    tree[rt].rc=0;
    tree[rt].maxx=0;
    tree[rt].sum=0;
}
void del(int &rt,int l,int r,int pos){
    if(l==r){
        clear(rt);
        rt=0;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) del(tree[rt].lc,l,mid,pos);
    else del(tree[rt].rc,mid+1,r,pos);
    tree[rt].maxx=max(tree[tree[rt].lc].maxx,tree[tree[rt].rc].maxx);
    tree[rt].sum=tree[tree[rt].lc].sum+tree[tree[rt].rc].sum;
    if(!tree[rt].rc&&!tree[rt].lc){
        clear(rt);
        rt=0;    
    }
}
long long querymax(int rt,int l,int r,int l1,int r1){
    if(!rt) return 0;
    if(l>=l1&&r<=r1) return tree[rt].maxx;
    int mid=(l+r)>>1;
    long long ans=0;
    if(l1<=mid) ans=max(ans,querymax(tree[rt].lc,l,mid,l1,r1));
    if(r1>mid) ans=max(ans,querymax(tree[rt].rc,mid+1,r,l1,r1));
    return ans;
}
long long querysum(int rt,int l,int r,int l1,int r1){
    if(!rt) return 0;
    if(l>=l1&&r<=r1) return tree[rt].sum;
    int mid=(l+r)>>1;
    long long ans=0;
    if(l1<=mid) ans+=querysum(tree[rt].lc,l,mid,l1,r1);
    if(r1>mid) ans+=querysum(tree[rt].rc,mid+1,r,l1,r1);
    return ans;
}
long long linkmax(int x,int y){
    int start=faith[x];
    long long ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans=max(ans,querymax(root[start],1,n,id[top[x]],id[x]));
        x=fa[top[x]];
    }
    if(dep[x]<dep[y]) swap(x,y);
    ans=max(ans,querymax(root[start],1,n,id[y],id[x]));
    return ans;
}
long long linksum(int x,int y){
    int start=faith[x];
    long long ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans+=querysum(root[start],1,n,id[top[x]],id[x]);
        x=fa[top[x]];
    }
    if(dep[x]<dep[y]) swap(x,y);
    ans+=querysum(root[start],1,n,id[y],id[x]);
    return ans;
}
void linkup1(int x,int y){
    level[x]=y;
    build(root[faith[x]],1,n,level[x],id[x]);
}
void linkup2(int x,int y){    
    del(root[faith[x]],1,n,id[x]);
    faith[x]=y;
    build(root[faith[x]],1,n,level[x],id[x]);
}
int main(){
    scanf("%d%d",&n,&q);
    for(register int i=1;i<=n;i++) scanf("%d%d",&level[i],&faith[i]);
    for(register int i=1;i<n;i++){
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }
    dfs1(1,0);
    dfs2(1,1);
    for(register int i=1;i<=n;i++) build(root[faith[i]],1,n,level[i],id[i]);
    for(register int i=1;i<=q;i++){
        scanf("%s",opt);
        scanf("%d%d",&x,&y);
        if(opt[0]=='C'){
            if(opt[1]=='C') linkup2(x,y);
            else linkup1(x,y);
        }
        if(opt[0]=='Q'){
            if(opt[1]=='M') printf("%lld\n",linkmax(x,y));
            else printf("%lld\n",linksum(x,y));
        }
    }
    return 0;
} 
View Code

 

上一篇:P3317 [SDOI2014]重建


下一篇:[转载].net程序集自动生成版本号