bzoj1036 树的统计Count 树链剖分 线段树

6 篇文章 0 订阅
3 篇文章 0 订阅

bzoj1036 树的统计Count
题目大意:树上修改点权 求路径上Max和Sum n<=3w q<=20w
题解:树链剖分上= =
树链剖分
很开心 我的代码要比别人的短= =

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=200010;
const int inf=0x7fffffff;
struct E {int to,nxt;}edge[M*2];
struct SEG {int l,r,sum,mx;}tree[M*2];
int v[M],fa[M],size[M],son[M],dep[M],top[M],w[M],f[M];
int n,q,tot=1,idx[M],vis[M],cnt,retsum,retmax;
void addedge(int from,int to){
    edge[tot].to=to;edge[tot].nxt=idx[from];idx[from]=tot++;
}
void init(){
    scanf("%d",&n);
    for(int i=1;i<n;i++) {int x,y;scanf("%d%d",&x,&y);addedge(x,y);addedge(y,x);}
    for(int i=1;i<=n;i++) scanf("%d",&v[i]);
}
void dfs(int x){
    vis[x]=1;size[x]=1;
    for(int t=idx[x];t;t=edge[t].nxt){
        E e=edge[t];
        if(!vis[e.to]){
            fa[e.to]=x;dep[e.to]=dep[x]+1;
            dfs(e.to);
            if(size[son[x]]<size[e.to]) son[x]=e.to;
            size[x]+=size[e.to];
        }
    }
}
void dfs2(int x,int tp){
    w[x]=++cnt;f[cnt]=x;top[x]=tp;
    if(son[x]!=0) dfs2(son[x],tp);
    for(int t=idx[x];t;t=edge[t].nxt){
        E e=edge[t];
        if(e.to!=son[x] && e.to!=fa[x]) dfs2(e.to,e.to);
    }
}
void build_seg(int k,int a,int b){
    tree[k].l=a;tree[k].r=b;
    if(a==b){tree[k].mx=v[f[a]];tree[k].sum=v[f[a]];return;}
    int mid=(a+b)>>1;
    build_seg(k<<1,a,mid);build_seg(k<<1|1,mid+1,b);
    tree[k].mx=max(tree[k<<1].mx,tree[k<<1|1].mx);
    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
void change(int k,int a,int x){
    if(a<tree[k].l || a>tree[k].r) return;
    if(a==tree[k].l && a==tree[k].r)
        {tree[k].mx=x,tree[k].sum=x;return;}
    change(k<<1,a,x);change(k<<1|1,a,x);
    tree[k].mx=max(tree[k<<1].mx,tree[k<<1|1].mx);
    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
int getsum(int k,int a,int b){
    if(b<tree[k].l || a>tree[k].r) return 0;
    if(a<=tree[k].l && tree[k].r<=b) return tree[k].sum;
    return getsum(k<<1,a,b)+getsum(k<<1|1,a,b);
}
int getmax(int k,int a,int b){
    if(b<tree[k].l || a>tree[k].r) return -inf;
    if(a<=tree[k].l && tree[k].r<=b) return tree[k].mx;
    return max(getmax(k<<1,a,b),getmax(k<<1|1,a,b));
}
void solve(int x,int y,int opt){
    int f1=top[x],f2=top[y];
    retmax=-inf,retsum=0;
    while(f1!=f2){
        if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
        if(opt) retmax=max(retmax,getmax(1,w[f1],w[x]));
        if(!opt) retsum+=getsum(1,w[f1],w[x]);
        x=fa[f1];f1=top[x];
    }
    if(opt) retmax=max(retmax,getmax(1,min(w[x],w[y]),max(w[x],w[y])));
    if(!opt) retsum+=getsum(1,min(w[x],w[y]),max(w[x],w[y]));
}
int main(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    init();
    dfs(1);
    dfs2(1,1);
    //for(int i=1;i<=n;i++) printf("%d ",w[i]);
    scanf("%d\n",&q);
    build_seg(1,1,n);
    //for(int i=1;i<=10;i++) printf("%d %d\n",i,tree[i].mx);
    for(int i=1;i<=q;i++){
        char s[10];int x,y;
        scanf("%s",s);
        scanf("%d%d\n",&x,&y);
        if(s[0]=='C') change(1,w[x],y);
        if(s[1]=='M') {solve(x,y,1);printf("%d\n",retmax);}
        if(s[1]=='S') {solve(x,y,0);printf("%d\n",retsum);}
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值