zoukankan      html  css  js  c++  java
  • 2017-3-26四校联考

    丧病出题人 我比较菜 只写了T1 100/400

    T1.约会

    题目大意:一棵树,每个点i有权值wi,支持三种操作:1.给定x,询问随机选出i!=j且lca(i,j)=x,wi+wj的期望;2.使一个点的权值加上k;3.使一棵子树内所有点的权值加上k。(n,操作数<=300,000)

    思路:对于一个lca(i,j)=x,选出的i和j必然在不同的子树内或者就在x,则

    $$ ans[x]=frac{2*(sum (sum[son[x]]*(size[x]-size[son[x]])) +w[x]*(size[x]-1))}{sum (size[son[x]]*(size[x]-size[son[x]]))+size[x]-1} $$

    ,先预处理出每个点的答案的式子的前半及后半的值,修改单点点权,会使该点及其祖先的答案发生更改,自己的答案把前半式子展开后发现可以O(1)修改,对祖先的修改我们先进行树剖,从一条重链跳到另一条时直接O(1)修改,若在重链上,用mx[x]表示x的重链连向的儿子,则重链上的点的前半式子会被修改k*(size[x]-size[mx[x]]),用线段树维护区间加k,处理询问使再乘上(size[x]-size[mx[x]])即可;再考虑子树加,显然子树内的所有点答案都会加上2k,而这次修改对祖先的贡献的计算方法与单点修改同理。总复杂度O(nlogn^2)(常数较小)。

    #include<cstdio>
    #define ll long long
    inline int read()
    {
        int x,f=1;char c;
        while((c=getchar())<'0'||c>'9')if(c=='-')f=0;
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return f?x:-x;
    }
    #define MN 300000
    #define N 524288
    struct edge{int nx,t;}e[MN+5];
    int h[MN+5],en,l[MN+5],r[MN+5],cnt,f[MN+5],fa[MN+5],mx[MN+5],s[MN+5];
    long double a[MN+5];
    ll w[MN+5],b[MN+5],t1[N*2+5],t2[N*2+5];
    inline void ins(int x,int y){e[++en]=(edge){h[x],y};h[x]=en;}
    void dfs(int x)
    {
        s[x]=1;a[x]=-w[x];
        for(int i=h[x];i;i=e[i].nx)
        {
            fa[e[i].t]=x;dfs(e[i].t);
            s[x]+=s[e[i].t];w[x]+=w[e[i].t];
            if(s[e[i].t]>s[mx[x]])mx[x]=e[i].t;
            a[x]-=w[e[i].t]*s[e[i].t];
            b[x]-=1LL*s[e[i].t]*s[e[i].t];
        }
        a[x]+=w[x]*s[x];
        b[x]+=1LL*s[x]*s[x]-1;
    }
    void build(int x,int k)
    {
        l[x]=++cnt;f[x]=k;
        if(mx[x])build(mx[x],k);
        for(int i=h[x];i;i=e[i].nx)if(e[i].t!=mx[x])build(e[i].t,e[i].t);
        r[x]=cnt;
    }
    void add(ll*t,int l,int r,ll x)
    {
        for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1)t[l+1]+=x;
            if( r&1)t[r-1]+=x;
        }
    }
    ll query(ll*t,int k){ll r=0;for(k+=N;k;k>>=1)r+=t[k];return r;}
    void up(int x,ll z)
    {
        for(;;)
        {
            if(x!=f[x])add(t2,l[f[x]],l[x]-1,z);
            if(!fa[f[x]])return;
            a[fa[f[x]]]+=(s[fa[f[x]]]-s[f[x]])*z;
            x=fa[f[x]];
        }
    }
    int main()
    {
        freopen("meet.in","r",stdin);
        freopen("meet.out","w",stdout);
        int n,m,i,x;char t[5];
        n=read();m=read();
        for(i=2;i<=n;++i)ins(read(),i);
        for(i=1;i<=n;++i)w[i]=read();
        dfs(1);build(1,1);
        while(m--)
        {
            scanf("%s",t);i=read();
            if(t[0]=='Q')printf("%.6lf
    ",
            (double)(s[i]>1?2*(query(t1,l[i])+(a[i]+(long double)query(t2,l[i])*(s[i]-s[mx[i]]))/b[i]):0));
            if(t[0]=='S')a[i]+=1LL*(s[i]-1)*(x=read()),up(i,x);
            if(t[0]=='M')add(t1,l[i],r[i],x=read()),up(i,1LL*(r[i]-l[i]+1)*x);
        }
        fclose(stdin);fclose(stdout);return 0;
    }

    T3.山脉

    题目大意:一条山脉由n个点组成,每个点有一个高度,高度大于左右两个点的称作山峰,每次把一个区间内的高度全部加上一个公差为正的等差数列,并询问此时有多少座山峰。(n,操作数<=100,000,出现的数字的绝对值<=100,000)

    思路:显然先把原数组差分,问题转化为每次修改两个点,区间加正数,询问有多少相邻的数字一个大于0一个小于0,先算一遍答案,修改两个点我们可以直接暴力,区间加显然只会当负数变为0或正数、0变成正数时会使答案变化,由于一开始负数/0最多n个,之后每次操作最多使负数/0增多2个,所以这个变化发生的次数最多是O(n)的,我们用线段树维护区间中最大的负数/0,如果区间加后区间内最大的负数非负了或者0超过0了,我们直接修改他,重复这个过程,总复杂度O(nlogn)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    inline int read()
    {
        int x,f=1;char c;
        while((c=getchar())<'0'||c>'9')if(c=='-')f=0;
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return f?x:-x;
    }
    #define MN 100000
    #define N 131072
    #define INF (1LL<<60)
    #define L (k<<1)
    #define R (k<<1|1)
    ll a[MN+5];int ans[N*2+5];
    void change(int k,int x){for(ans[k+=N]=x;k>>=1;)ans[k]=ans[L]+ans[R];}
    struct data
    {
        ll mf,m0;int pf,p0;
        data(ll mf=0,int pf=0,ll m0=0,int p0=0):mf(mf),pf(pf),m0(m0),p0(p0){}
        data(int x){pf=p0=x;mf=a[x]<0?a[x]:-INF;m0=a[x]?-INF:0;}
        inline friend data operator+(data a,data b)
        {
            return data(max(a.mf,b.mf),a.mf>b.mf?a.pf:b.pf,
                        max(a.m0,b.m0),a.m0>b.m0?a.p0:b.p0);
        }
        inline void operator+=(ll x){mf+=x;m0+=x;}
    };
    struct node{int l,r;ll mk;data x;}t[MN*4+5];
    inline void up(int k){t[k].x=t[L].x+t[R].x;}
    inline void add(int k,ll x){t[k].x+=x;t[k].mk+=x;}
    inline void down(int k){if(t[k].mk)add(L,t[k].mk),add(R,t[k].mk),t[k].mk=0;}
    void build(int k,int l,int r)
    {
        if((t[k].l=l)==(t[k].r=r)){t[k].x=data(l);return;}
        int mid=l+r>>1;
        build(L,l,mid);build(R,mid+1,r);up(k);
    }
    ll query(int k,int x)
    {
        while(t[k].l<t[k].r)down(k),k=x>t[k].l+t[k].r>>1?R:L;
        return a[t[k].l]+t[k].mk;
    }
    void add(int k,int x,ll ad)
    {
        while(t[k].l<t[k].r)down(k),k=x>t[k].l+t[k].r>>1?R:L;
        a[t[k].l]+=t[k].mk+ad;t[k].mk=0;
        change(x,query(1,x-1)>0&&a[t[k].l]<0);
        change(x+1,a[t[k].l]>0&&query(1,x+1)<0);
        t[k].x=data(t[k].l);
        while(k>>=1)up(k);
    }
    void add(int k,int l,int r,int ad)
    {
        if(t[k].l==l&&t[k].r==r){add(k,ad);return;}
        int mid=t[k].l+t[k].r>>1;down(k);
        if(r<=mid)add(L,l,r,ad);
        else if(l>mid)add(R,l,r,ad);
        else add(L,l,mid,ad),add(R,mid+1,r,ad);
        up(k);
    }
    data query(int k,int l,int r)
    {
        if(t[k].l==l&&t[k].r==r)return t[k].x;
        int mid=t[k].l+t[k].r>>1;down(k);
        if(r<=mid)return query(L,l,r);
        if(l>mid)return query(R,l,r);
        return query(L,l,mid)+query(R,mid+1,r);
    }
    int main()
    {
        int n,m,i,l,r,a1,d;data x;
        n=read();m=read();
        for(i=1;i<=n;++i)a[i]=read();
        for(i=1;i<n;++i)a[i]=a[i+1]-a[i];a[n]=0;
        for(i=2;i<n;++i)if(a[i-1]>0&&a[i]<0)change(i,1);
        build(1,0,n);
        printf("%d
    ",ans[1]);
        while(m--)
        {
            l=read();r=read();a1=read();d=read();
            if(l>1)add(1,l-1,a1);
            if(l<r)for(add(1,l,r-1,d);;)
                if((x=query(1,l,r)).mf>=0)add(1,x.pf,0);
                else if(x.m0>0)add(1,x.p0,0);
                else break;
            if(r<n)add(1,r,-a1-1LL*(r-l)*d);
            printf("%d
    ",ans[1]);
        }
    }
  • 相关阅读:
    ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(4)之业务仓储工厂
    ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(3)之创建实体层
    ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(2)之创建项目
    ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(1)之数据库设计
    ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(开篇)
    jQuery验证码发送时间秒递减(刷新存储cookie)
    闲来无事写一个jquery计算器,没有进行封装......
    ASP.NET MVC4.0+EF+LINQ+bui+网站+角色权限管理系统(7)
    <script runat=server>、<%%>和<%#%>的区别
    .net 实现 URL重写,伪静态
  • 原文地址:https://www.cnblogs.com/ditoly/p/20170326C.html
Copyright © 2011-2022 走看看