zoukankan      html  css  js  c++  java
  • bzoj 4127: Abs 树链剖分

    4127: Abs

    Time Limit: 40 Sec  Memory Limit: 256 MB
    Submit: 11  Solved: 5
    [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

      我们分开处理正数负数情况,注意加数为正,所以一个负数被加成正数最多发生O(n)次,我们需要实现的就是快速的判定是否有某个负数加成了正数,维护负数集合中的最大值和位置即可。如果负数集合的最大值大于0,那么我们求得最大值所在位置,然后暴力将它修改到正数集合即可。

      注意这道题INF取0x3f3f3f3f要出事。

      第一次写链剖的每个链单独建线段树版本,不是太难。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define MAXN 210000
    #define MAXT MAXN*4
    #define MAXV MAXN
    #define MAXE MAXN*2
    #define INFL 0x3f3f3f3f3f3f3f3f
    #define smid ((l+r)>>1)
    #define abs(x) ((x)>0?x:-(x))
    typedef long long qword;
    inline int nextInt()
    {
            register char ch;
            register int x=0;
            register bool f=false;
            while (ch=getchar(),ch<'0' || ch>'9')f|=ch=='-';
            while (x=x*10+ch-'0',ch=getchar(),ch<='9' && ch>='0');
            return x*(f?-1:1);
    }
    struct sgt_node
    {
            int lc,rc;
            int sd;
            qword sv;
            qword pls;
            pair<qword,int> mx;
    }sgt[MAXT];
    int topt=0;
    int a[MAXN];
    int b[MAXN];
    void update(int now)
    {
            sgt[now].mx=max(sgt[sgt[now].lc].mx,sgt[sgt[now].rc].mx);
            sgt[now].sd=sgt[sgt[now].lc].sd+sgt[sgt[now].rc].sd;
            sgt[now].sv=sgt[sgt[now].lc].sv+sgt[sgt[now].rc].sv;
    }
    void make_plus(int now,int l,int r,qword delta)
    {
            sgt[now].sv+=(qword)sgt[now].sd*delta;
            sgt[now].pls+=delta;
            sgt[now].mx.first+=delta;
    }
    void down(int now,int l,int r)
    {
            if (sgt[now].pls)
            {
                    make_plus(sgt[now].lc,l,smid,sgt[now].pls);
                    make_plus(sgt[now].rc,smid+1,r,sgt[now].pls);
                    sgt[now].pls=0;
            }
    }
    void Build_sgt(int &now,int l,int r)
    {
            now=++topt;
            if (l==r)
            {
                    sgt[now].sd=b[l]<0?-1:1;
                    sgt[now].sv=abs(b[l]);
                    if (b[l]<0)
                    {
                            sgt[now].mx=make_pair(b[l],l);
                    }else
                    {
                            sgt[now].mx=make_pair(-INFL,-1);
                    }
                    return ;
            }
            Build_sgt(sgt[now].lc,l,smid);
            Build_sgt(sgt[now].rc,smid+1,r);
            update(now);
    }
    void Add_sgt(int now,int l,int r,int x,int y,int delta)
    {
            if (l==x && r==y)
            {
                    make_plus(now,l,r,delta);
                    return ;
            }
            down(now,l,r);
            if (y<=smid)
                    Add_sgt(sgt[now].lc,l,smid,x,y,delta);
            else if (smid<x)
                    Add_sgt(sgt[now].rc,smid+1,r,x,y,delta);
            else
            {
                    Add_sgt(sgt[now].lc,l,smid,x,smid,delta);
                    Add_sgt(sgt[now].rc,smid+1,r,smid+1,y,delta);
            }
            update(now);
    }
    void Modify_sgt(int now,int l,int r,int pos,qword v)
    {
            if (l==r)
            {
                    if (v<0)
                            sgt[now].mx=make_pair(v,l);
                    else
                            sgt[now].mx=make_pair(-INFL,-1);
                    sgt[now].sd=v<0?-1:1;
                    sgt[now].sv=abs(v);
                    sgt[now].pls=0;
                    return ;
            }
            down(now,l,r);
            if (pos<=smid)
                    Modify_sgt(sgt[now].lc,l,smid,pos,v);
            else
                    Modify_sgt(sgt[now].rc,smid+1,r,pos,v);
            update(now);
    }
    pair<qword,int> Query_sgt_max(int now,int l,int r,int x,int y)
    {
            if (l==x && r==y)
            {
                    return sgt[now].mx;
            }
            down(now,l,r);
            if (y<=smid)
                    return Query_sgt_max(sgt[now].lc,l,smid,x,y);
            else if (smid<x)
                    return Query_sgt_max(sgt[now].rc,smid+1,r,x,y);
            else
                    return max(Query_sgt_max(sgt[now].lc,l,smid,x,smid),
                                    Query_sgt_max(sgt[now].rc,smid+1,r,smid+1,y));
    }
    qword Query_sgt_sum(int now,int l,int r,int x,int y)
    {
            if (l==x && r==y)
                    return sgt[now].sv;
            down(now,l,r);
            if (y<=smid)
                    return Query_sgt_sum(sgt[now].lc,l,smid,x,y);
            else if (smid<x)
                    return Query_sgt_sum(sgt[now].rc,smid+1,r,x,y);
            else
                    return Query_sgt_sum(sgt[now].lc,l,smid,x,smid)+
                            Query_sgt_sum(sgt[now].rc,smid+1,r,smid+1,y);
    }
    struct Edge
    {
            int np;
            Edge *next;
    }E[MAXE],*V[MAXV];
    int tope=-1;
    void addedge(int x,int y)
    {
            E[++tope].np=y;
            E[tope].next=V[x];
            V[x]=&E[tope];
    }
    int q[MAXN];
    int depth[MAXN],top[MAXN],son[MAXN];
    int pnt[MAXN],siz[MAXN];
    int pos[MAXN],dfstime;
    int spos[MAXN],tpos[MAXN];
    void bfs(int now)
    {
            int head=-1,tail=0;
            Edge *ne;
            q[0]=now;
            depth[now]=1;
            while (head<tail)
            {
                    now=q[++head];
                    for (ne=V[now];ne;ne=ne->next)
                    {
                            if (ne->np==pnt[now])continue;
                            pnt[ne->np]=now;
                            depth[ne->np]=depth[now]+1;
                            q[++tail]=ne->np;
                    }
            }
            for (int i=tail;i>=0;i--)
            {
                    now=q[i];
                    siz[now]=1;
                    int mxsiz=0;
                    for (ne=V[now];ne;ne=ne->next)
                    {
                            if (ne->np==pnt[now])continue;
                            siz[now]+=siz[ne->np];
                            if (siz[ne->np]>mxsiz)
                            {
                                    mxsiz=siz[ne->np];
                                    son[now]=ne->np;
                            }
                    }
            }
    }
    int stack[MAXN],tops=-1;
    void dfs(int now)
    {
            Edge *ne;
            memset(spos,0x3f,sizeof(spos));
            memset(tpos,0,sizeof(tpos));
            stack[++tops]=now;
            top[now]=now;
            while (~tops)
            {
                    now=stack[tops--];
                    pos[now]=++dfstime;
                    tpos[top[now]]=max(tpos[top[now]],pos[now]);
                    spos[top[now]]=min(spos[top[now]],pos[now]);
                    for (ne=V[now];ne;ne=ne->next)
                    {
                            if (ne->np==pnt[now] || ne->np==son[now])continue;
                            stack[++tops]=ne->np;
                            top[ne->np]=ne->np;
                    }
                    if (son[now])
                    {
                            stack[++tops]=son[now];
                            top[son[now]]=top[now];
                    }
            }
    }
    int troot[MAXN];
    
    int main()
    {
            freopen("input.txt","r",stdin);
            int n,m,x,y,z;
            scanf("%d%d",&n,&m);
            for (int i=1;i<=n;i++)
                    a[i]=nextInt();
            for (int i=1;i<n;i++)
            {
                    x=nextInt();y=nextInt();
                    //scanf("%d%d",&x,&y);
                    addedge(x,y);
                    addedge(y,x);
            }
            bfs(1);
            dfs(1);
            for (int i=1;i<=n;i++)
                    b[pos[i]]=a[i];
            for (int i=1;i<=n;i++)
            {
                    if (top[i]==i)
                            Build_sgt(troot[i],spos[i],tpos[i]);
                    else
                            troot[i]=-1;
            }
            int opt;
            for (int i=0;i<m;i++)
            {
                    opt=nextInt();
                    //scanf("%d",&opt);
                    if (opt==1)
                    {
                            x=nextInt();y=nextInt();z=nextInt();
                            //scanf("%d%d%d",&x,&y,&z);
                            while (true)
                            {
                                    if (top[x]==top[y])
                                    {
                                            if (pos[x]>pos[y])swap(x,y);
                                            Add_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pos[x],pos[y],z);
                                            while (true)
                                            {
                                                    pair<qword,int> pr;
                                                    pr=Query_sgt_max(troot[top[x]],spos[top[x]],tpos[top[x]],pos[x],pos[y]);
                                                    if (pr.first<=0)break;
                                                    Modify_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pr.second,pr.first);
                                            }
                                            break;
                                    }
                                    if (depth[top[x]]<depth[top[y]])swap(x,y);
                                    Add_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pos[top[x]],pos[x],z);
                                    while (true)
                                    {
                                            pair<qword,int> pr;
                                            pr=Query_sgt_max(troot[top[x]],spos[top[x]],tpos[top[x]],pos[top[x]],pos[x]);
                                            if (pr.first<=0)break;
                                            Modify_sgt(troot[top[x]],spos[top[x]],tpos[top[x]],pr.second,pr.first);
                                    }
                                    x=pnt[top[x]];
                            }
                    }else
                    {
                            //scanf("%d%d",&x,&y);
                            x=nextInt();y=nextInt();
                            qword res=0;
                            while (true)
                            {
                                    if (top[x]==top[y])
                                    {
                                            if (pos[x]>pos[y])swap(x,y);
                                            res+=Query_sgt_sum(troot[top[x]],spos[top[x]],tpos[top[x]],pos[x],pos[y]);
                                            break;
                                    }
                                    if (depth[top[x]]<depth[top[y]])swap(x,y);
                                    res+=Query_sgt_sum(troot[top[x]],spos[top[x]],tpos[top[x]],pos[top[x]],pos[x]);
                                    x=pnt[top[x]];
                            }
                            printf("%lld
    ",res);
                    }
            }
    }
  • 相关阅读:
    scala文件读取报错“java.nio.charset.MalformedInputException: Input length = 1”
    关于sparksql操作hive,读取本地csv文件并以parquet的形式装入hive中
    区别window.location.Reload()和window.location.href=window.location.href;
    datagrid GridView Repeater 绑定 序号 逐一递增的实现
    品牌机用Vista光盘分区
    网络路径结点回溯分析工具
    几种流行的AJAX框架jQuery,Mootools,Dojo,Ext JS的对比
    Ubuntu Linux 设置
    sql server中为某个整数前加上一定数量的0,如1,要返回00001
    本地测试域名
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4558421.html
Copyright © 2011-2022 走看看