zoukankan      html  css  js  c++  java
  • 【BZOJ-4353】Play with tree 树链剖分

    4353: Play with tree

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 31  Solved: 19
    [Submit][Status][Discuss]

    Description

    给你一棵包含N个节点的树,设每条边一开始的边权为0,现在有两种操作:
    1)给出参数U,V,C,表示把U与V之间的路径上的边权变成C(保证C≥0)
    2)给出参数U,V,C,表示把U与V之间的路径上的边权加上C。但是如果U至V之间路径某条边的边权加上C小于0,那么C=这条边的边权的相反数。
    你需要统计出每次一操作过后树中边权为0的边有多少条。

    Input

    第一行两个整数N,M,分别表示表示节点个数与操作数。
    接下来N-1行每行两个整数X,Y表示X,Y之间有一条边。
    接下来M行每行4个整数P,U,V,C,P表示操作类型,U,V,C的意义见题目描述。

    Output

    输出文件包括M行,每行一个整数,表示边权为0的边的个数。

    Sample Input

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

    Sample Output

    2
    0
    1
    3

    HINT

    N, M≤100,000

    Source

    Solution

    就是两个操作:1.树链覆盖C 2.树链+C,如果有边+C<0 则C=-minx

    随便链剖一下+线段树维护一下就可以了

    维护最小值minx,最小值个数minn

    覆盖的时候直接覆盖,+C的时候先查询minx再看看是否修改C,然后+C...输出答案就是,如果minx=0,ans+=minn....

    边权的树链剖分,就是把边权下放至点权

    边<u,v>的值,由u,v中较深的点保存,这样显然除了root每条边和每个点是一一对应的.

    这里查询所有边的值,因为默认1为root,所以直接查询[2,N]的就可以了。修改的时候稍微做一下修改就可以了

    所以说随便写写就A了.

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while (ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
        while (ch>='0'&&ch<='9') {x=10*x+ch-'0'; ch=getchar();}
        return x*f;
    }
    #define MAXN 100010
    struct EdgeNode{int next,to;}edge[MAXN<<1];
    int head[MAXN],cnt=1;
    void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
    void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}
    int N,M;
    #define INF 0x7fffffff
    namespace SegmentTree
    {
        struct SegmentTreeNode{int l,r,size,minx,minn,tag,del;}tree[MAXN<<2];
        #define ls now<<1
        #define rs now<<1|1
        inline void Update(int now)
        {
            tree[now].minx=min(tree[ls].minx,tree[rs].minx);
            tree[now].minn=tree[ls].minx<tree[rs].minx? tree[ls].minn:tree[rs].minn;
            if (tree[ls].minx==tree[rs].minx) tree[now].minx=tree[ls].minx,tree[now].minn=tree[ls].minn+tree[rs].minn;
        }
        inline void PushDown(int now)
        {
            if (tree[now].del!=-1)
                {
                    tree[ls].minx=tree[now].del; tree[ls].minn=tree[ls].size; tree[ls].del=tree[now].del; tree[ls].tag=0;
                    tree[rs].minx=tree[now].del; tree[rs].minn=tree[rs].size; tree[rs].del=tree[now].del; tree[rs].tag=0;
                    tree[now].del=-1;
                }
            if (tree[now].tag)
                {
                    tree[ls].minx+=tree[now].tag; tree[ls].tag+=tree[now].tag;
                    tree[rs].minx+=tree[now].tag; tree[rs].tag+=tree[now].tag;
                    tree[now].tag=0;
                }
        }
        inline void BuildTree(int now,int l,int r)
        {
            tree[now].l=l,tree[now].r=r,tree[now].size=r-l+1;
            tree[now].del=-1; tree[now].tag=0;
            if (l==r) {tree[now].minn=1; tree[now].minx=0; return;}
            int mid=(l+r)>>1;
            BuildTree(ls,l,mid);
            BuildTree(rs,mid+1,r);
            Update(now);
        }
        inline void Change(int now,int L,int R,int C)  
        {
            int l=tree[now].l,r=tree[now].r;
            if (L<=l && R>=r) {tree[now].tag+=C; tree[now].minx+=C; return;}    
            PushDown(now);
            int mid=(l+r)>>1;
            if (L<=mid) Change(ls,L,R,C);
            if (R>mid) Change(rs,L,R,C);
            Update(now);
        }
        inline void Modify(int now,int L,int R,int C)  
        {
            int l=tree[now].l,r=tree[now].r;
            if (L<=l && R>=r) {tree[now].del=C; tree[now].tag=0; tree[now].minx=C; tree[now].minn=tree[now].size; return;}
            PushDown(now);
            int mid=(l+r)>>1;
            if (L<=mid) Modify(ls,L,R,C);
            if (R>mid) Modify(rs,L,R,C);
            Update(now);
        }
        inline int Getmin(int now,int L,int R)
        {
            int l=tree[now].l,r=tree[now].r;
            if (L<=l && R>=r) return tree[now].minx;
            PushDown(now);
            int mid=(l+r)>>1,re=INF;
            if (L<=mid) re=min(re,Getmin(ls,L,R));
            if (R>mid) re=min(re,Getmin(rs,L,R));
            return re;
        }
        inline int Query(int now,int L,int R)
        {
            int l=tree[now].l,r=tree[now].r;
            if (L<=l && R>=r) return tree[now].minx==0? tree[now].minn:0;
            PushDown(now);
            int mid=(l+r)>>1,re=0;
            if (L<=mid) re+=Query(ls,L,R);
            if (R>mid) re+=Query(rs,L,R);
            return re;
        }
    }
    namespace ChainPartition
    {
        int size[MAXN],fa[MAXN],deep[MAXN],top[MAXN],pl[MAXN],pr[MAXN],pre[MAXN],dfn,son[MAXN];
        void DFS_1(int now)
        {
            size[now]=1;
            for (int i=head[now]; i; i=edge[i].next)
                if (edge[i].to!=fa[now])
                    {
                        deep[edge[i].to]=deep[now]+1;
                        fa[edge[i].to]=now;
                        DFS_1(edge[i].to);
                        size[now]+=size[edge[i].to];
                        if (size[son[now]]<size[edge[i].to]) son[now]=edge[i].to;
                    }
        }
        void DFS_2(int now,int chain)
        {
            top[now]=chain; pl[now]=++dfn; pre[dfn]=now;
            if (son[now]) DFS_2(son[now],chain);
            for (int i=head[now]; i; i=edge[i].next)
                if (edge[i].to!=fa[now] && edge[i].to!=son[now])
                    DFS_2(edge[i].to,edge[i].to);
            pr[now]=dfn;
        }
        inline int Get(int x,int y)
        {
            int re=INF;
            while (top[x]!=top[y])
                {
                    if (deep[top[x]]<deep[top[y]]) swap(x,y);
                    re=min(re,SegmentTree::Getmin(1,pl[top[x]],pl[x]));
                    x=fa[top[x]];
                }
            if (deep[x]>deep[y]) swap(x,y);
            if (x!=y) re=min(re,SegmentTree::Getmin(1,pl[x]+1,pl[y]));
            return re;
        }
        inline void Change(int x,int y,int C)
        {
            int minx=Get(x,y);
            if (minx+C<0) C=-minx;
    //        printf("Change   %d %d %d
    ",x,y,C);
            while (top[x]!=top[y])
                {
                    if (deep[top[x]]<deep[top[y]]) swap(x,y);
                    SegmentTree::Change(1,pl[top[x]],pl[x],C);
                    x=fa[top[x]];
                }
            if (deep[x]>deep[y]) swap(x,y);
            if (x!=y) SegmentTree::Change(1,pl[x]+1,pl[y],C);
            printf("%d
    ",SegmentTree::Query(1,2,N));
        }
        inline void Modify(int x,int y,int C)
        {
    //        printf("Modify   %d %d %d
    ",x,y,C);
            while (top[x]!=top[y])
                {
                    if (deep[top[x]]<deep[top[y]]) swap(x,y);
                    SegmentTree::Modify(1,pl[top[x]],pl[x],C);
                    x=fa[top[x]];
                }
            if (deep[x]>deep[y]) swap(x,y);
            if (x!=y) SegmentTree::Modify(1,pl[x]+1,pl[y],C);
            printf("%d
    ",SegmentTree::Query(1,2,N));
        }
    }
    int main()
    {
        N=read(),M=read();
        for (int x,y,i=1; i<=N-1; i++) x=read(),y=read(),InsertEdge(x,y);
        ChainPartition::DFS_1(1); ChainPartition::DFS_2(1,1);
        SegmentTree::BuildTree(1,1,N);
        while (M--)
            {
                int opt=read(),u=read(),v=read(),C=read();
                switch (opt)
                    {
                        case 1: ChainPartition::Modify(u,v,C); break;
                        case 2: ChainPartition::Change(u,v,C); break;
                    }
            }
        return 0;
    }

    以前看蛋蛋写了好几天....还找Claris要代码.....

    1h左右就A了....不过无故弄了个本题第一个RE

    ShallWe:"这不是傻逼题么?"

  • 相关阅读:
    总结几种常见web攻击手段及其防御方式(转)
    使用Chrome DevTools的Timeline分析页面性能(转)
    Sublime Text 无法使用Package Control或插件安装失败的解决方法(转)
    typeScript笔记
    ProtoBuf.js – Protocol Buffers的Javascript实现(转)
    JS到JAVA反射
    cocos 优化方案相关参考
    PMP学习笔记 (二)
    PMP学习笔记 (一)
    CentOS7安装GLPI资产管理系统
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5885235.html
Copyright © 2011-2022 走看看