MnZn刚学OI,全RE求助
查看原帖
MnZn刚学OI,全RE求助
154295
kkksc0019楼主2022/11/22 20:47

rt

#include<cstdio>
#include<iostream>
#define int long long
using namespace std;
const int maxn=100001;
int n,m,r,p;
int head[maxn],ver[maxn*2],nex[maxn*2],tot;
void add(int x,int y)
{
    ver[++tot]=y;
    nex[tot]=head[x],head[x]=tot;
} 
int son[maxn],fa[maxn],size[maxn],deep[maxn];
void dfs_getson(int x)
{
    size[x]=1;//初始化子树x的大小 
    for(int i=head[x];i;i=nex[i])//遍历x点连接的每一条边 
    {
        int y=ver[i];
        if(y==fa[x]) continue;//y是x父结点,跳过
        fa[y]=x;//y点父结点为x
        deep[y]=deep[x]+1;//y点所在深度为x点+1
        dfs_getson(y);//获取子树y的信息
        size[x]+=size[y];//子树x的大小要加上子树y的大小
        if(size[y]>size[son[x]]) son[x]=y;//更新x点的重儿子 
    } 
}
int dfn_past[maxn],dfn_new[maxn],top[maxn],cnt,ctr[maxn];
void dfs_rewrite(int x,int tp)//tp是x所在重链深度最小的那个点(顶点)
{
    top[x]=tp;
    dfn_new[x]=++tot;//得到每个点的新dfn 
    dfn_past[tot]=x;//记录新dfn所对应的原来的点
    if(son[x]) dfs_rewrite(son[x],tp);//优先遍历x点的重儿子
    for(int i=head[x];i;i=nex[i]) 
    {
        int y=ver[i];
        if(y!=fa[x]&&y!=son[x]) dfs_rewrite(y,y);//y点是轻儿子,成为新重链的顶点 
    }
    ctr[x]=cnt;//在回溯的时候标记这个子树的最大编号(新) 
} 
int point[maxn];//存点权 
//线段树part
struct Node{
    int l,r,add,val;
}t[maxn*4];
void build(int p,int l,int r,int a[])//在a数组(形参)上建线段树 
{
    t[p].l=l,t[p].r=r;
    if(l==r)
    {
        t[p].val=a[l]%p;
        return;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid,a);
    build(p<<1|1,mid+1,r,a);
    t[p].val=(t[p<<1].val+t[p<<1|1].val)%p;
} 
void spread(int p)
{
    if(t[p].add)
    {
        t[p<<1].add=(t[p<<1].add+t[p].add)%p;
        t[p<<1|1].add=(t[p<<1|1].add+t[p].add)%p;
        t[p<<1].val=(t[p<<1].val+t[p].add*(t[p<<1].r-t[p<<1].l+1))%p;
        t[p<<1|1].val=(t[p<<1|1].val+t[p].add*(t[p<<1|1].r-t[p<<1].l+1))%p;
        t[p].add=0;
    }
}
void update(int p,int l,int r,int k)
{
    if(l<=t[p].l&&r>=t[p].r)
    {
        t[p].add=(t[p].add+k)%p;
        t[p].val=(t[p].val+(t[p].r-t[p].l+1)*k)%p;
        return;
    }
    spread(p);
    int mid=(t[p].r+t[p].l)>>1;
    if(l<=mid) update(p<<1,l,r,k);
    if(r>mid) update(p<<1|1,l,r,k);
    t[p].val=(t[p<<1].val+t[p<<1|1].val)%p;
}
int query_sum(int p,int l,int r)
{
    if(l<=t[p].l&&r>=t[p].r)
     return t[p].val%p;
    spread(p);
    int mid=(t[p].r+t[p].l)>>1,val=0;
    if(l<=mid) val=(val+query_sum(p<<1,l,r))%p;
    if(r>mid) val=(val+query_sum(p<<1|1,l,r))%p;
    return val%p;
}
int query_max(int p,int l,int r)
{
    if(l<=t[p].l&&r>=t[p].r)
     return t[p].val%p;
    spread(p);
    int mid=(t[p].r+t[p].l)>>1,val=0;
    if(l<=mid) val=max(query_max(p<<1,l,r),val)%p;
    if(r>mid) val=max(query_max(p<<1|1,l,r),val)%p;
    return val%p;
}
//下面是树上操作
void tree_update()//树上修改
{
    int u,v,k;//u到v路径上所有点权增加k
    scanf("%lld%lld%lld",&u,&v,&k);
    while(top[u]!=top[v])//当两点不在同一条重链上
    {
        if(deep[top[u]]>deep[top[v]]) swap(u,v);//优先跳重链顶点深的,存在v里面 
        update(1,dfn_new[top[v]],dfn_new[v],k);//v到它所在重链顶点的新编号是连续的~
        v=fa[top[v]];//v点往上跳 
    }
    if(deep[u]>deep[v]) swap(u,v);//在同一条重链上的点,深度小的编号也小
    update(1,dfn_new[u],dfn_new[v],k);//同上 
}
void tree_query_sum()//树上路径点权和查询,和上面差不多 
{
    int u,v,ans;
    scanf("%lld%lld",&u,&v);
    while(top[u]!=top[v])
    {
        if(deep[top[u]]>deep[top[v]]) swap(u,v);
        ans+=query_sum(1,dfn_new[top[v]],dfn_new[v]);
        v=fa[top[v]];
    }
    if(deep[u]>deep[v]) swap(u,v);
    ans+=query_sum(1,dfn_new[u],dfn_new[v]);
    printf("%lld\n",ans);
}
void tree_query_max()//树上路径最大点权,和上面差不多 
{
    int u,v,ans;
    scanf("%lld%lld",&u,&v);
    while(top[u]!=top[v])
    {
        if(deep[top[u]]>deep[top[v]]) swap(u,v);
        ans=max(ans,query_max(1,dfn_new[top[v]],dfn_new[v]));
        v=fa[top[v]];
    }
    if(deep[u]>deep[v]) swap(u,v);
    ans=max(ans,query_max(1,dfn_new[u],dfn_new[v]));
    printf("%lld\n",ans);
}
//下面是关于子树的操作 
void sontree_update()
{
    int x,k;
    scanf("%lld%lld",&x,&k);//子树x内所有点点权+k 
    update(1,dfn_new[x],ctr[x],k);//因为编号连续就可以直接update
}
void sontree_query_sum()
{
    int x;
    scanf("%lld%lld",&x);//查询子树x点权和 
    printf("%lld\n",query_sum(1,dfn_new[x],ctr[x])); 
}
void sontree_query_max()
{
    int x;
    scanf("%lld%lld",&x);//查询子树x中最大点权 
    printf("%lld\n",query_max(1,dfn_new[x],ctr[x])); 
}
signed main()
{
    scanf("%lld%lld%lld%lld",&n,&m,&r,&p);
    int opt,x,y;
    for(int i=1;i<=n;i++)
     scanf("%lld",&point[i]);
    for(int i=1;i<n;i++)
    {
        scanf("%lld%lld",&x,&y);
        add(x,y);
        add(y,x);
    }
    dfs_getson(r);
    dfs_rewrite(r,r);
    build(1,1,n,point);
    for(int i=1;i<=m;i++)
    {
        scanf("%lld",&opt);
        if(opt==1) tree_update();
        if(opt==2) tree_query_sum();
        if(opt==3) sontree_update();
        if(opt==4) sontree_query_sum(); 
    }
    return 0;
}
2022/11/22 20:47
加载中...