[洛谷4242]树上的毒瘤

路径权值计算与树链剖分求解
博客介绍了如何分段求出题目中的\(T(i,j)\),通过建立虚树,以\(T(u,v)-1\)为边权进行动态规划。还提到二次换根可\(O(n)\)求出所有特殊点的\(f[i]\),对于颜色修改使用树链剖分求解,最后指出代码量较大。

题目传送门:https://www.luogu.org/problemnew/show/P4242

首先我们考虑如何把题目求的\(T(i,j)\)分段求出,假定在路径\(<i,j>\)上找到一些关键点\(p_0,p_2,...p_k\),其中\(p_0=i,p_k=j\),可以发现\(\sum\limits_{i=1}^kT(p_{i-1},p_i)-k+1=T(i,j)\),于是我们把虚树建出来之后,对于边\(<u,v>\),可以直接用\(T(u,v)-1\)作为其边权,然后在虚树上dp,记\(f[i]\)表示到其子树内所有特殊点的路径权值和(在虚树上),然后对于\(f[i]\)输出\(f[i]+cnt\)即可(\(cnt\)为特殊点个数)

二次换根即可\(O(n)\)求出所有特殊点的\(f[i]\),然后由于有颜色修改,我们使用树链剖分即可(貌似这个写法跑得飞快)

码量有点小大

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1; char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1; char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=1e5;
int dfn[N+10],ID[N+10],V[N+10],n,q;
bool cmp(int x,int y){return ID[x]<ID[y];}
struct S1{
    #define ls (p<<1)
    #define rs (p<<1|1)
    struct node{
        int l,r,sum;
        node(){l=r=sum=0;}
        node(int _l,int _r,int _sum){l=_l,r=_r,sum=_sum;}
        void init(int v){l=r=v,sum=1;}
    }tree[(N<<2)+10];
    int cov[(N<<2)+10];
    friend node operator +(const node &x,const node &y){
        if (!x.sum) return y;
        if (!y.sum) return x;
        return node(x.l,y.r,x.sum+y.sum-(x.r==y.l));
    }
    void Add_cov(int p,int v){
        tree[p].init(v);
        cov[p]=v;
    }
    void pushdown(int p){
        if (!cov[p])    return;
        Add_cov(ls,cov[p]);
        Add_cov(rs,cov[p]);
        cov[p]=0;
    }
    void build(int p,int l,int r){
        if (l==r){
            tree[p].init(V[dfn[l]]);
            return;
        }
        int mid=(l+r)>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
        tree[p]=tree[ls]+tree[rs];
    }
    void Modify(int p,int l,int r,int x,int y,int v){
        if (x<=l&&r<=y){
            Add_cov(p,v);
            return;
        }
        pushdown(p);
        int mid=(l+r)>>1;
        if (x<=mid) Modify(ls,l,mid,x,y,v);
        if (y>mid)  Modify(rs,mid+1,r,x,y,v);
        tree[p]=tree[ls]+tree[rs];
    }
    node Query(int p,int l,int r,int x,int y){
        if (x<=l&&r<=y) return tree[p];
        pushdown(p);
        int mid=(l+r)>>1; node res;
        if (x<=mid) res=res+Query(ls,l,mid,x,y);
        if (y>mid)  res=res+Query(rs,mid+1,r,x,y);
        return res;
    }
    #undef ls
    #undef rs
}ST;//Segment Tree
struct S2{
    int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],tot,Time;
    int size[N+10],fa[N+10],deep[N+10],top[N+10],Rem[N+10];
    void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
    void insert(int x,int y){join(x,y),join(y,x);}
    void dfs(int x){
        deep[x]=deep[fa[x]]+1,size[x]=1;
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]) continue;
            fa[son]=x,dfs(son);
            size[x]+=size[son];
            if (size[Rem[x]]<size[son]) Rem[x]=son;
        }
    }
    void build(int x){
        if (!x) return;
        dfn[ID[x]=++Time]=x;
        top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
        build(Rem[x]);
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]||son==Rem[x])    continue;
            build(son);
        }
    }
    int LCA(int x,int y){
        while (top[x]!=top[y]){
            if (deep[top[x]]<deep[top[y]])  swap(x,y);
            x=fa[top[x]];
        }
        return deep[x]<deep[y]?x:y;
    }
    void Modify(int x,int y,int v){
        while (top[x]!=top[y]){
            if (deep[top[x]]<deep[top[y]])  swap(x,y);
            ST.Modify(1,1,n,ID[top[x]],ID[x],v);
            x=fa[top[x]];
        }
        if (deep[x]>deep[y])    swap(x,y);
        ST.Modify(1,1,n,ID[x],ID[y],v);
    }
    int Query(int x,int y){
        S1::node res;
        while (top[x]!=top[y]){
            if (deep[top[x]]<deep[top[y]])  swap(x,y);
            res=ST.Query(1,1,n,ID[top[x]],ID[x])+res;
            x=fa[top[x]];
        }
        if (deep[x]>deep[y])    swap(x,y);
        res=ST.Query(1,1,n,ID[x],ID[y])+res;
        return res.sum;
    }
}HLD;//Heavy Light Decomposition
struct S3{
    int pre[(N<<1)+10],now[N+10],child[(N<<1)+10],val[(N<<1)+10];
    int A[N+10],stack[N+10],size[N+10];
    int m,tot; ll f[N+10];
    bool mark[N+10];
    void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
    void insert(int x,int y,int z=0){z=HLD.Query(x,y)-1,join(x,y,z),join(y,x,z);}
    void rebuild(){
        int top=0; tot=0;
        sort(A+1,A+1+m,cmp);
        stack[++top]=1;
        for (int i=1;i<=m;i++){
            int x=A[i],lca=HLD.LCA(x,stack[top]);
            if (x==1)   continue;
            if (lca==stack[top]){
                stack[++top]=x;
                continue;
            }
            while (true){
                int y=stack[top-1];
                if (ID[y]>=ID[lca]) insert(y,stack[top--]);
                else{
                    if (lca==stack[top])    break;
                    insert(stack[top],lca);
                    stack[top]=lca; break;
                }
            }
            stack[++top]=x;
        }
        while (top>1){
            insert(stack[top],stack[top-1]);
            top--;
        }
    }
    void dfs1(int x,int fa){
        size[x]=mark[x],f[x]=0;
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa)    continue;
            dfs1(son,x),size[x]+=size[son];
            f[x]+=f[son]+1ll*val[p]*size[son];
        }
    }
    void dfs2(int x,int fa){//二次换根
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa)    continue;
            f[son]=f[x]+1ll*val[p]*(m-2ll*size[son]);
            dfs2(son,x);
        }
        now[x]=0;
    }
    void work(){
        static int list[N+10];
        m=read();
        for (int i=1;i<=m;i++)  mark[list[i]=A[i]=read()]=1;
        rebuild(),dfs1(1,0),dfs2(1,0);
        for (int i=1;i<=m;i++)  printf("%lld",f[list[i]]+m),putchar(i==m?'\n':' ');
        for (int i=1;i<=m;i++)  mark[A[i]]=0;
    }
}VT;//Virtual Tree
int main(){
    n=read(),q=read();
    for (int i=1;i<=n;i++)  V[i]=read();
    for (int i=1;i<n;i++){
        int x=read(),y=read();
        HLD.insert(x,y);
    }
    HLD.dfs(1),HLD.build(1),ST.build(1,1,n);
    for (int i=1;i<=q;i++){
        int type=read();
        if (type==1){
            int x=read(),y=read(),v=read();
            HLD.Modify(x,y,v);
        }
        if (type==2)    VT.work();
    }
    return 0;
}

转载于:https://www.cnblogs.com/Wolfycz/p/10573226.html

T23713 [愚人节题目2]数据结构大毒瘤 提交答案加入题单复制题目 提交 1.47k 通过 273 时间限制 1.00s 内存限制 125.00MB 题目编号 T23713 提供者 洛谷官方团队 难度 暂无评定 历史分数 暂无 提交记录 标签 洛谷原创 推荐题目 暂无 复制 Markdown 展开 进入 IDE 模式 题目背景 这是一道毒瘤题 这题太难了,所以窝先卖个萌0=w=0 窝从没出过这么难的题!!!! 题目描述 你好啊~这是一道数据结构毒瘤题~ 您需要维护一个数列S~ 有7种操作,形如w a b c w=0 输出S a ​ +S a+1 ​ +...+S b ​ 。c没有用 w=1 将[S a ​ ,S b ​ ]翻转。c没有用 w=2 将[S a ​ ,S b ​ ]内的数全部加上c。 w=3 将[S a ​ ,S b ​ ]内的数全部乘上c。 w=4 将[S a ​ ,S b ​ ]内的数全部开根号。c没有用 w=5 将S a ​ 加上c,将S a+1 ​ 加上2c,...,将S b ​ 加上c*(b-a+1) w=6 将[S a ​ ,S b ​ ]和[S b+1 ​ ,S c ​ ]交换。保证c-b=b-a+1。 输入格式 第一行是n和m,n表示初始序列的长度,m表示操作数量 然后n个整数,表示初始序列S 之后m行每行四个数w a b c,代表一个操作 输出格式 对于每个0操作,输出一行表示答案 输入输出样例 输入 #1复制 5 1 1 2 3 4 5 0 1 2 3 输出 #1复制 3 说明/提示 样例解释 第一次操作,询问的答案为1+2=3 数据范围 1≤n,m≤5×10 4 ,0≤w≤9,1≤a≤b≤n 保证任何时候S i ​ ∈[−10 9 ,10 9 ] 保证输入所有数∈[−10 9 ,10 9 ]
最新发布
07-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值