zoukankan      html  css  js  c++  java
  • [BZOJ]4127: Abs

    题解:    我们考虑  $ d>0 $  然后对于每一个负数  只有一次从负数到正数的变化  所以我们考虑  把每一个临界点的修改都拿出来暴力改掉  然后维护答案就行

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <cmath>
    #include <set>
    #include <map>
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define link(x) for(edge *j=h[x];j;j=j->next)
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=3e5+10;
    const double eps=1e-8;
    #define ll long long
    using namespace std;
    const ll inf=2e18;
    struct edge{int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
    void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    
    int fa[MAXN],dep[MAXN],son[MAXN],num[MAXN],n,m,a[MAXN];
    void dfs1(int x,int pre,int deep){
        dep[x]=deep+1;fa[x]=pre;num[x]=1;
        link(x){
    	if(j->t==pre)continue;
    	dfs1(j->t,x,deep+1);
    	num[x]+=num[j->t];
    	if(son[x]==-1||num[son[x]]<num[j->t])son[x]=j->t;
        }
    }
    
    int p[MAXN],fp[MAXN],cnt,tp[MAXN];
    void dfs2(int x,int td){
        tp[x]=td;p[x]=++cnt;fp[p[x]]=x;
        if(son[x]!=-1)dfs2(son[x],td);
        link(x)if(j->t!=fa[x]&&j->t!=son[x])dfs2(j->t,j->t);
    }
    
    ll maxx[MAXN<<2],Num[MAXN<<2];
    ll tag[MAXN<<2],sum[MAXN<<2];
    void up(int x){
        maxx[x]=max(maxx[x<<1],maxx[x<<1|1]);
        sum[x]=sum[x<<1]+sum[x<<1|1];
        Num[x]=Num[x<<1]+Num[x<<1|1];
    }
    
    void push(int x,int l,int r){
        if(tag[x]){
    	int mid=(l+r)>>1;
    	tag[x<<1]+=tag[x];tag[x<<1|1]+=tag[x];
    	if(maxx[x<<1]!=-inf)maxx[x<<1]+=tag[x];
    	if(maxx[x<<1|1]!=-inf)maxx[x<<1|1]+=tag[x];
    	sum[x<<1]+=tag[x]*(mid-l+1-2*Num[x<<1]);
    	sum[x<<1|1]+=tag[x]*(r-mid-2*Num[x<<1|1]);
    	tag[x]=0;
        }
    }
    
    void built(int x,int l,int r){
        sum[x]=tag[x]=0;
        if(l==r){
    	if(a[fp[l]]<0)Num[x]=1,maxx[x]=a[fp[l]],sum[x]=-a[fp[l]];
    	else Num[x]=0,maxx[x]=-inf,sum[x]=a[fp[l]];
    	return ;
        }
        int mid=(l+r)>>1;
        built(x<<1,l,mid);
        built(x<<1|1,mid+1,r);
        up(x);
    }
    
    void update(int x,int l,int r,int t,int k){
        if(l==r){
    	Num[x]=0;maxx[x]=-inf;sum[x]=k;
    	return ;
        }
        int mid=(l+r)>>1;
        push(x,l,r);
        if(t<=mid)update(x<<1,l,mid,t,k);
        else update(x<<1|1,mid+1,r,t,k);
        up(x);
    }
    
    void update1(int x,int l,int r,int ql,int qr,int t){
        if(ql<=l&&r<=qr){
    	tag[x]+=t;sum[x]+=1ll*t*(r-l+1-2*Num[x]);
    	if(maxx[x]!=-inf)maxx[x]+=t;
    	return ;
        }
        int mid=(l+r)>>1;
        push(x,l,r);
        if(ql<=mid)update1(x<<1,l,mid,ql,qr,t);
        if(qr>mid)update1(x<<1|1,mid+1,r,ql,qr,t);
        up(x);
    }
    
    ll ans;
    void query(int x,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr){ans+=sum[x];return ;}
        int mid=(l+r)>>1;
        push(x,l,r);
        if(ql<=mid)query(x<<1,l,mid,ql,qr);
        if(qr>mid)query(x<<1|1,mid+1,r,ql,qr);
        up(x);
    }
    
    vector<pii>vec;
    
    void query1(int x,int l,int r,int ql,int qr,int d){
        if(ql<=l&&r<=qr){
    	if(maxx[x]<-d)return ;
    	if(l==r){vec.pb(mp(l,maxx[x]));return ;}
        }
        int mid=(l+r)>>1;
        push(x,l,r);
        if(ql<=mid)query1(x<<1,l,mid,ql,qr,d);
        if(qr>mid)query1(x<<1|1,mid+1,r,ql,qr,d);
        up(x);
    }
    
    void solve(int x,int y,int d){
        vec.clear();
        query1(1,1,n,x,y,d);
        //for(int i=0;i<vec.size();i++)cout<<vec[i].first<<":::";
        //cout<<endl;
        int l=x;
        for(int i=0;i<vec.size();i++){
    	update(1,1,n,vec[i].first,d+vec[i].second);
    	if(l<vec[i].first)update1(1,1,n,l,vec[i].first-1,d);
    	l=vec[i].first+1;
        }
        if(l<=y)update1(1,1,n,l,y,d);
    }
    
    void work1(int u,int v,int d){
        int uu=tp[u];int vv=tp[v];
        while(uu!=vv){
    	if(dep[uu]<dep[vv])swap(uu,vv),swap(u,v);
    	solve(p[uu],p[u],d);
    	u=fa[uu];uu=tp[u];
        }
        if(dep[u]>dep[v])swap(u,v);
        solve(p[u],p[v],d);
    }
    
    void work2(int u,int v){
        int uu=tp[u];int vv=tp[v];
        ll ans1=0;
        while(uu!=vv){
    	if(dep[uu]<dep[vv])swap(u,v),swap(uu,vv);
    	ans=0;query(1,1,n,p[uu],p[u]);ans1+=ans;
    	u=fa[uu];uu=tp[u];
        }
        if(dep[u]>dep[v])swap(u,v);
        ans=0;query(1,1,n,p[u],p[v]);ans1+=ans;
        printf("%lld
    ",ans1);
    }
    
    
    int main(){
        n=read();m=read();
        inc(i,1,n)a[i]=read(),son[i]=-1;
        int x,y,d;
        inc(i,2,n)x=read(),y=read(),add(x,y),add(y,x);
        dfs1(1,0,0);dfs2(1,1);
        built(1,1,n);
        int op;
        while(m--){
    	op=read();x=read();y=read();
    	if(op==1)d=read(),work1(x,y,d);
    	else work2(x,y);
        }
        return 0;
    }
    

      

    4127: Abs

    Time Limit: 40 Sec  Memory Limit: 256 MB
    Submit: 765  Solved: 261
    [Submit][Status][Discuss]

    Description

     给定一棵树,设计数据结构支持以下操作
    
        1 u v d  表示将路径 (u,v) 加d
    
        2 u v  表示询问路径 (u,v) 上点权绝对值的和

    Input

    第一行两个整数n和m,表示结点个数和操作数
    接下来一行n个整数a_i,表示点i的权值
    
    接下来n-1行,每行两个整数u,v表示存在一条(u,v)的边
    
    接下来m行,每行一个操作,输入格式见题目描述

    Output

    对于每个询问输出答案

    Sample Input

    4 4
    -4 1 5 -2
    1 2
    2 3
    3 4
    2 1 3
    1 1 4 3
    2 1 3
    2 3 4

    Sample Output

    10
    13
    9

    HINT

    对于100%的数据,n,m <= 10^5 且 0<= d,|a_i|<= 10^8

  • 相关阅读:
    20189315《网络攻防实践》第十周作业
    20189315《网络攻防实践》第九周作业
    20189315《网络攻防实践》第八周作业
    20189315《网络攻防实践》第七周作业
    20189315《网络攻防实践》第六周作业
    20189315《网络攻防实践》第五周作业
    20189315《网络攻防实践》第四周作业
    20189315《网络攻防实践》第三周作业
    20189315《网络攻防实践》第二周作业
    20189315《网络攻防实践》第一周作业
  • 原文地址:https://www.cnblogs.com/wang9897/p/10432849.html
Copyright © 2011-2022 走看看