Generating Synergy

一、题目

在这里插入图片描述

二、解法

考虑 k-d \text{k-d} k-d树,把每一个点以第一维 d f n dfn dfn序,第二维 d e p dep dep深度插入到二维空间中,修改的话就对第一维在 [ d f i n , d f o u ] [dfin,dfou] [dfin,dfou],第二维在 [ d e p , d e p + l ] [dep,dep+l] [dep,dep+l]中的点打标记,类似于平衡树的修改。

查询要注意一下,虽然只查询一个点,但是由于第二维会有相同权值,单点定位的方法是不行的,我们可以把点看成区间去查,虽然要复杂一些,但是保证了正确性且复杂度不变,我们在查询时顺便释放标记就可以了。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int M = 100005;
const double al = 0.7;
const int jzm = 1e9+7;
int read()
{
    int x=0,flag=1;char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int T,n,m,k,opt,ans,rt,cnt,tot,f[M],dfin[M],dfou[M],dep[M];
int Index,mi[M][2],mx[M][2],tag[M],col[M],ls[M],rs[M];
struct node
{
    int x[2];
}a[M],v[M];
struct edge
{
    int v,next;
    edge(int V=0,int N=0) : v(V) , next(N) {}
}e[M];
void up(int x)
{
    for(int i=0;i<2;i++)
        mi[x][i]=mx[x][i]=v[x].x[i];
    if(ls[x])
        for(int i=0;i<2;i++)
        {
            mx[x][i]=max(mx[x][i],mx[ls[x]][i]);
            mi[x][i]=min(mi[x][i],mi[ls[x]][i]);
        }
    if(rs[x])
        for(int i=0;i<2;i++)
        {
            mx[x][i]=max(mx[x][i],mx[rs[x]][i]);
            mi[x][i]=min(mi[x][i],mi[rs[x]][i]);
        }
}
int cmp(node a,node b)
{
    return a.x[opt]<b.x[opt];
}
void build(int &x,int l,int r,int wd)
{
    if(l>r) return ;
    x=++cnt;
    int mid=(l+r)>>1;
    opt=wd;
    nth_element(a+l,a+mid,a+r+1,cmp);
    v[x]=a[mid];col[x]=1;tag[x]=0;
    ls[x]=rs[x]=0;
    build(ls[x],l,mid-1,wd^1);
    build(rs[x],mid+1,r,wd^1);
    up(x);
}
int in(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4)
{
    return x1<=x3 && x4<=x2 && y1<=y3 && y4<=y2;
}
int out(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4)
{
    return x1>x4 || x2<x3 || y1>y4 || y2<y3;
}
void dfs(int u)
{
    dfin[u]=++Index;
    for(int i=f[u];i;i=e[i].next)
    {
        int v=e[i].v;
        dep[v]=dep[u]+1;
        dfs(v);
    }
    dfou[u]=Index;
    a[u].x[0]=dfin[u];
    a[u].x[1]=dep[u];
}
void down(int x)
{
    if(!tag[x]) return ;
    col[ls[x]]=col[rs[x]]=tag[ls[x]]=tag[rs[x]]=tag[x];
    tag[x]=0;
}
void modify(int x,int u,int l,int c)
{
    if(!x) return ;
    if(in(dfin[u],dep[u],dfou[u],dep[u]+l,mi[x][0],mi[x][1],mx[x][0],mx[x][1]))
    {
        tag[x]=col[x]=c;
        return ;
    }
    if(out(dfin[u],dep[u],dfou[u],dep[u]+l,mi[x][0],mi[x][1],mx[x][0],mx[x][1]))
        return ;
    if(in(dfin[u],dep[u],dfou[u],dep[u]+l,v[x].x[0],v[x].x[1],v[x].x[0],v[x].x[1]))
        col[x]=c;
    down(x);
    modify(ls[x],u,l,c);
    modify(rs[x],u,l,c);
}
int ask(int x,int u)
{
    if(!x) return 0;
    if(v[x].x[0]==dfin[u]) return col[x];
    if(out(dfin[u],dep[u],dfin[u],dep[u],mi[x][0],mi[x][1],mx[x][0],mx[x][1]))
        return 0;
    down(x);
    int t=ask(ls[x],u);
    if(t) return t;
    return ask(rs[x],u);
}
int main()
{
    T=read();
    while(T--)
    {
        tot=cnt=rt=Index=ans=0;memset(f,0,sizeof f);
        n=read();m=read();k=read();
        for(int j=2;j<=n;j++)
        {
            int i=read();
            e[++tot]=edge(j,f[i]),f[i]=tot;
        }
        dep[1]=1;
        dfs(1);
        build(rt,1,n,0);
        for(int i=1;i<=k;i++)
        {
            int u=read(),v=read(),c=read();
            if(c)
                modify(rt,u,v,c);
            else
            {
                int t=ask(rt,u);
                ans=(ans+1ll*i*t%jzm)%jzm;
            }
        }
        printf("%d\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值