zoukankan      html  css  js  c++  java
  • [3.26福建四校联考]

    来自FallDream的博客,未经允许,请勿转载,谢谢。

    ------------------------------------------------------------------------------------------

    我好菜啊都不会,ditoly轻松切掉T1,险些rank1,我死搞T3,到最后log^2都不会,真的菜。

    ------------------------------------------------------------------------------------------

    A.约会

    给定一棵n个节点的树,每个点有权值。m次操作1.单点加2.子树加3.求满足$lca(x,y)=z$的$w[x]+w[y]$的期望值。n,m<=300000

    题解:对于以点a为根的一棵子树,假设它有孩子x1..xk,size(x)表示子树x的大小,sum(x)表示子树x的权值和,w(x)表示点x的权值,那么点$lca(x,y)=a$的权值总和为:

    $(size(a)-size(x1))*sum(x1)+(size(a)-size(x1)*sum(x2)+..+(size(a)-size(k))*sum(k)+w(a)*(size(a)-1)$

    方案数同理,可以看作每一个点对的权值和都是1,那么我们把它展开得到所求的期望值是:

    $$frac{2*size(a)*sum(a)-sum_{i=1}^{k}sum(xk)*size(xk)-w(a)}{size(a)^2-sum_{i=1}^{k}size(xk)^{2}-1}$$

    两部分可以预处理,那么我们考虑处理修改操作对上面部分的影响。

    如果改的是一棵子树,那么可以看作所有点对的期望都实际增加了$2*ad$,我们在一棵线段树上区间改。

    如果改的是一个节点,那么代入公式我们会发现它实际增加了$2*ad*(size[x]-1)$,直接记下即可。

    处理完了修改操作对子树的影响,接下来要考虑对这个操作到跟节点的一条链上的节点的影响。

    同样带入公式,得到对于一个点a,修改的点在它的子树b中,对它的影响是$ad*(size(a)-size(b))$ 

    于是我们对这棵树树剖,然后最多只要处理logn条重链,对于重链上的点线段树区间修改,对于重链之间的连接点,直接暴力改它就好啦。

    复杂度$nlog^{2}n$

    #include<iostream>
    #include<cstdio>
    #define MN 300000
    #define ll long long
    #define ld long double
    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 = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    ld w1[MN+5];
    char op[5];
    ll sum[MN+5],w[MN+5],s1[MN+5];
    int size[MN+5],mx[MN+5],head[MN+5],cnt=0,dfn=0,n,m,top[MN+5],nl[MN+5],nr[MN+5],fa[MN+6];
    struct edge{int to,next;}e[MN+5]; 
    struct TREE{int l,r;ll x,val;}T1[MN*4+5],T2[MN*4+5],T3[MN*4+5];
    inline void ins(int f,int t){e[++cnt]=(edge){t,head[f]};head[f]=cnt;}
    
    void build(TREE*T,int x,int l,int r)
    {
        if((T[x].l=l)==(T[x].r=r))return;
        int mid=l+r>>1;
        build(T,x<<1,l,mid);build(T,x<<1|1,mid+1,r);
    }
    
    void pushdown(TREE*T,int x)
    {
        int l=x<<1,r=x<<1|1;
        T[l].x+=T[x].val;T[r].x+=T[x].val;
        T[l].val+=T[x].val;T[r].val+=T[x].val;
        T[x].val=0;
    }
    
    void renew(TREE*T,int x,int l,int r,ll ad)
    {
        if(T[x].l==l&&r==T[x].r) {T[x].x+=ad;T[x].val+=ad;return;}
        int mid=T[x].l+T[x].r>>1;
        if(r<=mid)renew(T,x<<1,l,r,ad);
        else if(l>mid)renew(T,x<<1|1,l,r,ad);
        else {renew(T,x<<1,l,mid,ad);renew(T,x<<1|1,mid+1,r,ad);}
    }
    
    ll query(TREE*T,int x,int k)
    {
        if(T[x].l==T[x].r)return T[x].x;    
        if(T[x].val!=0)pushdown(T,x);
        int mid=T[x].l+T[x].r>>1;
        return k<=mid?query(T,x<<1,k):query(T,x<<1|1,k);
    }
    
    void dfs1(int x)
    {
        size[x]=1;mx[x]=0;sum[x]=w[x];s1[x]=-1;w1[x]=-w[x];int maxn=0;
        for(int i=head[x];i;i=e[i].next)
        {
            dfs1(e[i].to);size[x]+=size[e[i].to];sum[x]+=sum[e[i].to];
            if(size[e[i].to]>maxn){maxn=size[e[i].to];mx[x]=e[i].to;}
            w1[x]-=size[e[i].to]*sum[e[i].to];s1[x]-=1LL*size[e[i].to]*size[e[i].to];
        }
        w1[x]+=sum[x]*size[x];s1[x]+=1LL*size[x]*size[x];
    } 
    
    void dfs2(int x,int tp)
    {
        nl[x]=++dfn;top[x]=tp;if(mx[x]) dfs2(mx[x],tp);
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=mx[x])dfs2(e[i].to,e[i].to);
        nr[x]=dfn;
    }
    
    void up(int x,ll ad)
    {
        for(;x!=0;x=fa[top[x]])
        {
            if(x!=top[x]) renew(T2,1,nl[top[x]],nl[x]-1,ad);
            if(fa[top[x]]) w1[fa[top[x]]]+=ad*(size[fa[top[x]]]-size[top[x]]);
        }
    }
    
    int main()
    {
        n=read();m=read();build(T1,1,1,n);build(T2,1,1,n);
        for(int i=2;i<=n;i++) ins(fa[i]=read(),i);
        for(int i=1;i<=n;i++) w[i]=read();
        dfs1(1);dfs2(1,1);
        for(int i=1;i<=m;i++)
        {
            scanf("%s",op);int x=read();
            if(op[0]=='Q'){printf("%.6f
    ",size[x]>1?2*query(T1,1,nl[x])+(double)2*(double)((double)w1[x]+(ld)query(T2,1,nl[x])*(size[x]-size[mx[x]]))/s1[x]:0);}
            else if(op[0]=='S'){int ad=read();w1[x]+=1LL*(size[x]-1)*ad;up(x,ad);}
            else {int ad=read();renew(T1,1,nl[x],nr[x],ad);up(x,1LL*(nr[x]-nl[x]+1)*ad);}
        }
        return 0;
    }

     3.山脉

    给定n座山,每座山都有一个高度,需要支持两个操作:1)给区间[l,r]加上一个首项为a,公差为d(>0)的等差数列 2)询问有多少个点比它两旁的点都大。$n,mleqslant 10^{5}$

    题解:很容易想到改为维护差分数组,这样题目转换为维护一个n-1个点的序列,每次修改两个单点和一段区间,求第一个是正的,第二个是负的的长度为2的区间的个数。

    由于区间加的公差d是正的,一开始最多有n-1个负数,每次操作最多加入一个负数,所以我们可以直接线段树维护区间最大的负数,每次找到最大的负数,判断是否会变成正数或者0,然后暴力更新答案,这个的次数是$O(n)$的,所以复杂度$O(nlogn)$

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #define MAXN 100000
    #define INF 200000000000LL
    #define ll long long
    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=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    int n,m;
    int s[MAXN+5],ans=0;
    vector<int> v;
    struct data
    {
        ll x;int from;
        data operator + (data y)
        {
            return ((y.x<=0&&y.x>=x)||x>0)?y:*this;
        }
    };
    struct TREE{int l,r;ll val;data x;}T[MAXN*4+5];
    
    void build(int x,int l,int r)
    {
        if((T[x].l=l)==(T[x].r=r)){T[x].x=(data){s[l],l};return;}
        int mid=l+r>>1;
        build(x<<1,l,mid);build(x<<1|1,mid+1,r);
        T[x].x=T[x<<1].x+T[x<<1|1].x;
    }
    
    void pushdown(int x)
    {
        int l=x<<1,r=x<<1|1;
        T[l].x.x+=T[x].val;T[r].x.x+=T[x].val;
        T[l].val+=T[x].val;T[r].val+=T[x].val;
        T[x].val=0;
    }
    
    void modify(int x,int l,int r,ll ad)
    {
        if(T[x].l==l&&T[x].r==r)
        {
            if(T[x].x.x<=0&&T[x].x.x+ad>=0&&l!=r)
            {
                T[x].x.x+=ad;T[x].val+=ad;pushdown(x);
                int mid=l+r>>1;
                modify(x<<1,l,mid,ad);modify(x<<1|1,mid+1,r,ad);
                T[x].x=T[x<<1].x+T[x<<1|1].x;
                return;
            }
            T[x].val+=ad;T[x].x.x+=ad;
            return;
        }
        if(T[x].val)pushdown(x);
        int mid=T[x].l+T[x].r>>1;
        if(r<=mid)modify(x<<1,l,r,ad);
        else if(l>mid)modify(x<<1|1,l,r,ad);
        else {modify(x<<1,l,mid,ad);modify(x<<1|1,mid+1,r,ad);}
        T[x].x=T[x<<1].x+T[x<<1|1].x;
    }
    
    data query(int x,int l,int r)
    {
        if(T[x].l==l&&r==T[x].r)return T[x].x;
        if(T[x].val)pushdown(x);int mid=T[x].l+T[x].r>>1;
        if(r<=mid) return query(x<<1,l,r);
        else if(l>mid)return query(x<<1|1,l,r);
        else return query(x<<1,l,mid)+query(x<<1|1,mid+1,r);
    }
    
    void calc(int x,int ad)
    {
        if(x!=1)ans-=(query(1,x,x).x<0&&query(1,x-1,x-1).x>0);
        if(x!=n-1)ans-=(query(1,x,x).x>0&&query(1,x+1,x+1).x<0);
        if(x!=1)ans+=(query(1,x,x).x+ad<0&&query(1,x-1,x-1).x>0);
        if(x!=n-1)ans+=(query(1,x,x).x+ad>0&&query(1,x+1,x+1).x<0); 
    }
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=n;i++)s[i]=read();
        for(int i=1;i<n;i++)s[i]=s[i+1]-s[i];
        for(int i=1;++i<n;)ans+=(s[i-1]>0&&s[i]<0);
        build(1,1,n-1);printf("%d
    ",ans);
        for(int i=1;i<=m;i++)
        {
            int l=read(),r=read(),a=read(),d=read();
            if(l>1)calc(l-1,a),modify(1,l-1,l-1,a);
            if(r<n)calc(r,-(a+(r-l)*d)),modify(1,r,r,-(a+d*(r-l)));
            if(l<r)
            {    
                data now=query(1,l,r-1);
                while(l<r&&now.x<=0&&now.x+d>=0)
                {
                    calc(now.from,d);
                    modify(1,now.from,now.from,INF);
                    v.push_back(now.from);
                    now=query(1,l,r-1);
                }
                modify(1,l,r-1,d);
                for(int j=0;j<v.size();j++)
                    modify(1,v[j],v[j],-INF);
                v.clear(); 
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    mongodb 3.4复制搭建
    mongodb 用户管理
    mongodb 3.4 TAR包启动多个实例
    mongodb 3.4 YUM安装
    mongodb数据库备份恢复-windows系统
    mongodb数据库索引管理
    mongodb数据库集合操作
    Unity3d 实现鼠标左键点击地形使角色移动到指定地点[脚本]
    Unity3D性能优化之Draw Call Batching
    Unity3D占用内存太大怎么解决呢?
  • 原文地址:https://www.cnblogs.com/FallDream/p/liankao326.html
Copyright © 2011-2022 走看看