zoukankan      html  css  js  c++  java
  • HDU6962:I love tree——题解

    https://acm.hdu.edu.cn/showproblem.php?pid=6962

    支持树上单点查询和路径修改,每次路径修改时按照路径起点到终点的顺序标号1,2,...,然后分别对这些点权+标号$^2$

    SB题我就是调不出来。

    退化成序列问题思考,对于一个区间[l,r]的修改,第一个数从x开始(即,l位置上的数要$+x^2$,以此类推),那么可以化为第i个数$+(x+l-i)^2$,不妨令$y=x+l$,即变成$(y-i)^2=y^2-2yi+i^2$,因此线段树分别维护三个值即可。

    这题恶心就恶心在强行上树然后树链剖分就需要讨论情况。当然你要想写麻烦点也可以通过什么LCA啊来判断每条链的加减情况。我就不想写麻烦于是开始了漫长的debug时光……

    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1e5+5;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct node{
        int to,nxt;
    }e[N<<1];
    struct tree{
        ll lazy[3];
    }t[N<<2];
    int head[N],cnt,tot,n,m,rt;
    int fa[N],pos[N],idx[N],son[N],size[N],dep[N],top[N];
    inline void add(int u,int v){
        e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
    }
    void dfs1(int u){
        size[u]=1;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(fa[u]==v)continue;
            fa[v]=u;dep[v]=dep[u]+1;
            dfs1(v);
            size[u]+=size[v];
            if(!son[u]||size[son[u]]<size[v])son[u]=v;
        }
    }
    void dfs2(int u,int anc){
        pos[u]=++tot;idx[tot]=u;top[u]=anc;
        if(!son[u])return;
        dfs2(son[u],anc);
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(v==fa[u]||v==son[u])continue;
            dfs2(v,v);
        }
    }
    inline void init(){
        dep[rt]=1;
        dfs1(rt);
        dfs2(rt,rt);
    }
    void pushdown(int a,int l,int r){
        if(t[a].lazy[2]){
            t[a<<1].lazy[0]+=t[a].lazy[0];
            t[a<<1|1].lazy[0]+=t[a].lazy[0];
            t[a<<1].lazy[1]+=t[a].lazy[1];
            t[a<<1|1].lazy[1]+=t[a].lazy[1];
            t[a<<1].lazy[2]+=t[a].lazy[2];
            t[a<<1|1].lazy[2]+=t[a].lazy[2];
            t[a].lazy[0]=0;t[a].lazy[1]=0;t[a].lazy[2]=0;
        }
        return;
    }
    inline ll query(int a,int l,int r,int x){
        if(l==r) return t[a].lazy[0]-t[a].lazy[1]*2*l+t[a].lazy[2]*l*l;
        int mid=(l+r)>>1;pushdown(a,l,r);
        if(x<=mid) return query(a<<1,l,mid,x);
        else return query(a<<1|1,mid+1,r,x);
    }
    inline void modify(int a,int l,int r,int l1,int r1,ll v){
        if(r1<l||r<l1)return;
        if(l1<=l&&r<=r1){
            t[a].lazy[0]+=v*v;
            t[a].lazy[1]+=v;
            t[a].lazy[2]+=1;
            return;
        }
        int mid=(l+r)>>1;pushdown(a,l,r);
        modify(a<<1,l,mid,l1,r1,v);modify(a<<1|1,mid+1,r,l1,r1,v);
    }
    struct rem{
        int l,r,op;
        rem(){}
        rem(int _l,int _r,int _op){l=_l;r=_r;op=_op;}
    }tmp[N];
    inline void mdf(int x,int y){
        int sum=0,o=0,op=0;
        while(top[x]!=top[y]){
            if(dep[top[x]]<dep[top[y]]){
                swap(x,y);op^=1;
            }
            tmp[++o]=rem(pos[top[x]],pos[x],op);sum+=pos[x]-pos[top[x]]+1;
            x=fa[top[x]];
        }
        if(dep[x]>dep[y]){
            swap(x,y);op^=1;
        }
        tmp[++o]=rem(pos[x],pos[y],op);sum+=pos[y]-pos[x]+1;
        int p1=1,p2=sum+1;
        for(int i=1;i<o;i++){
            if(!tmp[i].op){
                modify(1,1,n,tmp[i].l,tmp[i].r,tmp[i].r+p1);
                p1+=tmp[i].r-tmp[i].l+1;
            }else{
                p2-=tmp[i].r-tmp[i].l+1;
                modify(1,1,n,tmp[i].l,tmp[i].r,tmp[i].l-p2);
            }
        }
        if(!tmp[o].op){
            modify(1,1,n,tmp[o].l,tmp[o].r,tmp[o].l-p1);
            p1+=tmp[o].r-tmp[o].l+1;
        }else{
            p2-=tmp[o].r-tmp[o].l+1;
            modify(1,1,n,tmp[o].l,tmp[o].r,tmp[o].r+p2);
        }
    }
    inline ll qry(int x){
        return query(1,1,n,pos[x]);
    }
    int main(){
        n=read(),rt=1;
        for(int i=1;i<n;i++){
            int u=read(),v=read();
            add(u,v);add(v,u);
        }
        init();
        m=read();
        for(int i=1;i<=m;i++){
            int op=read();
            if(op==1){
                int x=read(),y=read();
                mdf(x,y);
            }
            if(op==2){
                int x=read();
                printf("%lld
    ",qry(x));
            }
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    SSL工作原理
    xmlhttprequest对象
    form验证的图片(小技巧)
    C#转码
    引用不了App_Code里的类
    再谈如何成为技术领袖
    如何做好年末总结?
    编程习惯
    软件人员推荐书目(都是国外经典书籍!!!)
    又当爹又当妈的产品经理
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/15050826.html
Copyright © 2011-2022 走看看