UOJ Logo zhouzixuan的博客

博客

bzoj 4127: Abs

2015-06-15 12:54:28 By zhouzixuan
【题目描述】:
    给定一棵树,设计数据结构支持以下操作
    1 u v d 表示将路径(u,v)加d
    2 u v 表示询问路径(u,v)上点权绝对值的和
【题目解法】:
    看似很不可做,因为有些树的符号在求和时要改变
    然而我们观察一下数据范围:对于100%的数据,n,m <= 10^5 且 0<= d,|a_i|<= 10^8
    为什么d没有绝对值符号呢?这样我们可以发现一条重要的结论:所有数最多只会从负数变成正数一次
    也就是说加入在某次+d后某个数由负数变成了正数,那么我们就暴力修改即可
    由于这样的暴力只会有n次,所以复杂度就是O(n log n),显然是用线段树实现
    然后只要维护区间最大负数值判断即可
【未完待续?】:
    如果d可以为负数怎么破?
【调整栈空间】:
    编译时加上  -Wl,--stack,10000000
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=100005;
const long long INF=(long long)3208320832083208;
struct node {long long maxt,sum1,sum2,lazy,num1,num2;} tree[N*4];
struct edge {int x,next;} b[N*2];
int n,m,tot,a[N],c[N],dfn[N]; long long ans,delta;
int dep[N],top[N],id[N],fa[N],son[N],size[N];
inline long long getint()
{
    long long x=0; char c=getchar(); bool flag=false;
    while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
    if (c=='-') flag=true,c=getchar();
    while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
    if (flag) return -x; else return x;
}
inline void addedge(int x,int y)
{
    ++tot; b[tot].x=y; b[tot].next=a[x]; a[x]=tot;
}
void init()
{
    n=getint(); m=getint();
    for (int i=1; i<=n; i++) c[i]=getint();
    for (int i=1; i<=n-1; i++) 
    {
        int x=getint(),y=getint(); 
        addedge(x,y); addedge(y,x);
    }
}
void dfs1(int x,int pre,int depth)
{
    fa[x]=pre; dep[x]=depth; size[x]=1; int k=0;
    for (int p=a[x];p;p=b[p].next)
    {
        int pp=b[p].x; if (pp==pre) continue;
        dfs1(pp,x,depth+1); size[x]+=size[pp];
        if (size[pp]>k) k=size[pp],son[x]=pp;
    }
}
void dfs2(int x,int ancestor)
{
    top[x]=ancestor; ++tot; id[x]=tot; dfn[tot]=x;
    if (son[x]!=0) dfs2(son[x],ancestor);
    for (int p=a[x];p;p=b[p].next)
    {
        int pp=b[p].x; if (pp==fa[x]) continue;
        if (pp==son[x]) continue; dfs2(pp,pp);
    }
}
void LCT()
{
    tot=0; dfs1(1,0,1); dfs2(1,1);
}
inline void lazy_tag(int p)
{
    if (tree[p].lazy==0) return;  int lc=p*2,rc=p*2+1;
    tree[lc].lazy+=tree[p].lazy;
    tree[rc].lazy+=tree[p].lazy;
    tree[lc].maxt+=tree[p].lazy;
    tree[rc].maxt+=tree[p].lazy;
    tree[lc].sum1+=(long long)tree[lc].num1*tree[p].lazy;
    tree[rc].sum1+=(long long)tree[rc].num1*tree[p].lazy;
    tree[lc].sum2+=(long long)tree[lc].num2*tree[p].lazy;
    tree[rc].sum2+=(long long)tree[rc].num2*tree[p].lazy;
    tree[p].lazy=0;
}
void build(int p,int l,int r)
{
    if (l==r)
    {
        int now=c[dfn[l]];
        if (now>=0) tree[p].maxt=-INF; else tree[p].maxt=now;
        if (now>=0) tree[p].sum1=now; else tree[p].sum2=now;
        if (now>=0) tree[p].num1=1; else tree[p].num2=1;
        return;
    }
    int mid=(l+r)/2;
    build(p*2,l,mid); build(p*2+1,mid+1,r);
    tree[p].maxt=max(tree[p*2].maxt,tree[p*2+1].maxt);
    tree[p].sum1=tree[p*2].sum1+tree[p*2+1].sum1;
    tree[p].sum2=tree[p*2].sum2+tree[p*2+1].sum2;
    tree[p].num1=tree[p*2].num1+tree[p*2+1].num1;
    tree[p].num2=tree[p*2].num2+tree[p*2+1].num2;
}
void modify(int p,int l,int r)
{
    if (l!=r) lazy_tag(p); int mid=(l+r)/2;
    if (!((tree[p].maxt<0)&&(tree[p].maxt+delta>=0)))
    {
        tree[p].lazy+=delta; tree[p].maxt+=delta;
        tree[p].sum1+=tree[p].num1*delta;
        tree[p].sum2+=tree[p].num2*delta;
        return;
    }
    if (l==r)
    {
        tree[p].maxt=-INF; tree[p].sum1=tree[p].sum2+delta;
        tree[p].sum2=0; tree[p].num1=1; tree[p].num2=0;
        return;
    }
    modify(p*2,l,mid); modify(p*2+1,mid+1,r);
    tree[p].maxt=max(tree[p*2].maxt,tree[p*2+1].maxt);
    tree[p].sum1=tree[p*2].sum1+tree[p*2+1].sum1;
    tree[p].sum2=tree[p*2].sum2+tree[p*2+1].sum2;
    tree[p].num1=tree[p*2].num1+tree[p*2+1].num1;
    tree[p].num2=tree[p*2].num2+tree[p*2+1].num2;
}
void getseg(int p,int l,int r,int ll,int rr)
{
    if (l!=r) lazy_tag(p); int mid=(l+r)/2;
    if ((l==ll)&&(r==rr)) {modify(p,l,r); return;}
    if (rr<=mid) getseg(p*2,l,mid,ll,rr);
    else if (ll>mid) getseg(p*2+1,mid+1,r,ll,rr);
    else getseg(p*2,l,mid,ll,mid),getseg(p*2+1,mid+1,r,mid+1,rr);
    tree[p].maxt=max(tree[p*2].maxt,tree[p*2+1].maxt);
    tree[p].sum1=tree[p*2].sum1+tree[p*2+1].sum1;
    tree[p].sum2=tree[p*2].sum2+tree[p*2+1].sum2;
    tree[p].num1=tree[p*2].num1+tree[p*2+1].num1;
    tree[p].num2=tree[p*2].num2+tree[p*2+1].num2;
}
long long ask(int p,int l,int r,int ll,int rr)
{
    if (l!=r) lazy_tag(p); int mid=(l+r)/2;
    if ((l==ll)&&(r==rr)) return tree[p].sum1-tree[p].sum2;
    if (rr<=mid) return ask(p*2,l,mid,ll,rr);
    else if (ll>mid) return ask(p*2+1,mid+1,r,ll,rr);
    else return ask(p*2,l,mid,ll,mid)+ask(p*2+1,mid+1,r,mid+1,rr);
}
void modify(int l,int r)
{
    while (top[l]!=top[r])
    {
        if (dep[top[l]]<dep[top[r]]) swap(l,r);
        getseg(1,1,n,id[top[l]],id[l]); l=fa[top[l]];
    }
    if (dep[l]>dep[r]) swap(l,r);
    getseg(1,1,n,id[l],id[r]);
}
void ask(int l,int r)
{
    ans=0;
    while (top[l]!=top[r])
    {
        if (dep[top[l]]<dep[top[r]]) swap(l,r);
        ans+=ask(1,1,n,id[top[l]],id[l]); l=fa[top[l]];
    }
    if (dep[l]>dep[r]) swap(l,r);
    ans+=ask(1,1,n,id[l],id[r]); printf("%I64d\n",ans);
}
void solve()
{
    for (int i=1; i<=m; i++)
    {
        int opt=getint();
        if (opt==1) {int x=getint(),y=getint(); delta=getint(); modify(x,y);}
        if (opt==2) {int x=getint(),y=getint(); ask(x,y);}
    }
}
int main()
{
    init();
    LCT();
    build(1,1,n);
    solve();
    return 0;
}
//!!I64d->lld

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。