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\n",qry(x));
        }
    }
    return 0;
}

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

+本文作者:luyouqi233。               +

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

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

posted @ 2021-07-23 20:38  luyouqi233  阅读(96)  评论(0编辑  收藏  举报