[bzoj4154][kdtree]Generating Synergy

6 篇文章 0 订阅

Description

给定一棵以1为根的有根树,初始所有节点颜色为1,每次将距离节点a不超过l的a的子节点染成c,或询问点a的颜色

Input

第一行一个数T,表示数据组数 接下来每组数据的第一行三个数n,c,q表示结点个数,颜色数和操作数 接下来一行n-1个数描述2..n的父节点
接下来q行每行三个数a,l,c 若c为0,表示询问a的颜色 否则将距离a不超过l的a的子节点染成c

Output

设当前是第i个操作,y_i为本次询问的答案(若本次操作是一个修改则y_i为0),令z_i=i*y_i,请输出z_1+z_2+…+z_q模10^9+7

Sample Input

1

4 3 7

1 2 2

3 0 0

2 1 3

3 0 0

1 0 2

2 0 0

4 1 1

4 0 0

Sample Output

32

HINT

第1,3,5,7的询问的答案分别为1,3,3,1,所以答案为 1*1+2*0+3*3+4*0+5*3+6*0+7*1=32.

数据范围:

对于100%的数据T<=6,n,m,c<=10^5,

1<=a<=n,0<=l<=n,0<=c<=c

题解

神啊我根本没有想过把他转化成一个二维矩阵的做法
第一维dfs序,第二维深度
于是就转化成了矩阵修改单点查询的问题
可以写二维线段树或者树套树?
不过上kdtree就可以了,写一个可以下传标记的
单点查询的时候向上找出父亲把遗传标记下放,修改的时候记得不要把标记动了。。因为这个调了一下午

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
struct node
{
    int lc,rc,d[2],mx[2],mn[2],c,op,f;
    bool lazy;
}tr[110000];
void upd(int now)
{
    int lc=tr[now].lc,rc=tr[now].rc;
    if(lc)for(int i=0;i<=1;i++)tr[now].mx[i]=max(tr[lc].mx[i],tr[now].mx[i]),tr[now].mn[i]=min(tr[lc].mn[i],tr[now].mn[i]);
    if(rc)for(int i=0;i<=1;i++)tr[now].mx[i]=max(tr[rc].mx[i],tr[now].mx[i]),tr[now].mn[i]=min(tr[rc].mn[i],tr[now].mn[i]);
}
int belong[110000];
int cmpd;
bool cmp(node n1,node n2){return n1.d[cmpd]<n2.d[cmpd];}
int bt(int l,int r,int f,int d)
{
    cmpd=d;
    int mid=(l+r)/2;int now=mid;
    nth_element(tr+l,tr+mid,tr+r+1,cmp);
    tr[now].mx[0]=tr[now].mn[0]=tr[now].d[0];
    tr[now].mx[1]=tr[now].mn[1]=tr[now].d[1];
    tr[now].f=f;
    belong[tr[now].op]=now;
    tr[now].lazy=false;
    if(l<mid)tr[now].lc=bt(l,mid-1,now,d^1);
    if(mid<r)tr[now].rc=bt(mid+1,r,now,d^1);
    upd(now);
    return now;
}
void lazy(int now)
{
    if(tr[now].lazy)
    {
        int lc=tr[now].lc,rc=tr[now].rc;
        if(lc)tr[lc].c=tr[now].c,tr[lc].lazy=true;
        if(rc)tr[rc].c=tr[now].c,tr[rc].lazy=true;
        tr[now].lazy=false;
    }
}
int xx1,yy1,xx2,yy2;//mn mx
void change(int now,int c)
{
    if(tr[now].mx[0]<xx1 || tr[now].mn[0]>xx2 || tr[now].mx[1]<yy1 || tr[now].mn[1]>yy2)return ;
    if(tr[now].mx[0]<=xx2 && tr[now].mx[1]<=yy2 && tr[now].mn[0]>=xx1 && tr[now].mn[1]>=yy1)
    {
        tr[now].c=c;tr[now].lazy=true;
        return ;
    }   
    if(tr[now].lazy)lazy(now);
    if(tr[now].d[0]>=xx1 && tr[now].d[0]<=xx2 && tr[now].d[1]>=yy1 && tr[now].d[1]<=yy2)tr[now].c=c;
    int lc=tr[now].lc,rc=tr[now].rc;
    if(lc)change(lc,c);
    if(rc)change(rc,c);
}
/*int nowx,nowy;
bool check(int now)
{
    if(now==0)return false;
    if(tr[now].mx[0]<nowx || tr[now].mn[0]>nowx)return false;
    if(tr[now].mx[1]<nowy || tr[now].mn[1]>nowy)return false;
    return true;    
}
int findcol(int now)
{
    if(tr[now].d[0]==nowx && tr[now].d[1]==nowy)return tr[now].c;
    int lc=tr[now].lc,rc=tr[now].rc;
    if(tr[now].lazy)lazy(now);
    int tx=-1;
    if(lc && check(lc))tx=findcol(lc);
    if(tx!=-1)return tx;
    if(rc && check(rc))return findcol(rc);
    return -1;
}*/
struct edge
{
    int x,y,next;   
}a[210000];int len,last[110000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;    
}
int in[110000],ot[110000],dfn;
int fa[110000],dep[110000];
void pre_tree_node(int x)
{
    in[x]=++dfn;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa[x])
        {
            fa[y]=x;
            dep[y]=dep[x]+1;
            pre_tree_node(y);
        }
    }
    ot[x]=dfn;
}
int tmp[110000],tp;
int findcol(int x)
{
    int s=x;tp=0;
    while(s!=0)tmp[++tp]=s,s=tr[s].f;
    while(tp)lazy(tmp[tp--]);
    return tr[x].c;
}
int n,col,q,root;
int main()
{
//  freopen("g1.in","r",stdin);
//  freopen("g.out","w",stdout);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        LL ans=0;
        scanf("%d%d%d",&n,&col,&q);
        len=0;memset(last,0,sizeof(last));
        for(int i=2;i<=n;i++)
        {
            int x;scanf("%d",&x);
            ins(x,i);
        }
        fa[1]=0;dep[1]=1;dfn=0;
        pre_tree_node(1);
        for(int i=1;i<=n;i++)
        {
            tr[i].d[0]=in[i];tr[i].d[1]=dep[i];
            tr[i].lc=tr[i].rc=0;
            tr[i].c=1;tr[i].op=i;
        }
        root=bt(1,n,0,0);
        for(int tt=1;tt<=q;tt++)
        {
            int op,u,x;
            scanf("%d%d%d",&u,&x,&op);
            if(op==0)
            {
                int tmp=findcol(belong[u]);
                //printf("%d\n",tmp);
                ans=(ans+(LL)tmp*tt)%mod;
            }
            else
            {
                xx1=in[u];xx2=ot[u];
                yy1=dep[u];yy2=dep[u]+x;
                change(root,op);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值