bzoj 4154: [Ipsc2015]Generating Synergy (KD-tree)

本文介绍了一个使用KD-tree解决树形结构中特定节点及其子节点染色及查询颜色的问题。通过构建KD-tree并利用其高效查询和更新特性,文章详细阐述了算法的具体实现过程,包括树的构建、节点查询和颜色更新等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4154: [Ipsc2015]Generating Synergy

Time Limit: 10 Sec   Memory Limit: 512 MB
Submit: 500   Solved: 200
[ Submit][ Status][ Discuss]

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




Source

[ Submit][ Status][ Discuss]

题解:KD-tree

其实这道题就是用KD-tree实现了一颗树套树,树套树的常数巨大,而且空间使用量也很感人。对于这道题的数据范围来说有点悬,而KD-tree虽然很暴力,但是一般的时间复杂度是低于理论复杂度的。

KD-tree的第一维表示的是dfs序,第二维表示的是点的深度。

查询的时候有点类似线段树的单点查询,不过因为每个节点都维护的是一个范围,所以无法直接确定在左右子树,只能两个子树都扫一下,找到就退出。

修改的时候如果整个区间都符合那么就打标机,否则暴力修改。

注意修改和查询的时候都要进行标记下放。

#include<iostream>    
#include<cstdio>    
#include<cstring>    
#include<algorithm>    
#include<cmath>    
#define N 200003    
#define p 1000000007    
#define LL long long    
using namespace std;    
int cmpd,n,m,q,tot,nxt[N],point[N],v[N],deep[N],l[N],r[N],pos[N],sz,root,T,c;    
struct data{    
    int d[2],mx[2],mn[2];    
    int l,r,mark,col;    
}now,tr[N];    
bool operator<(data a,data b)    
{    
    return a.d[cmpd]<b.d[cmpd];    
}    
void add(int x,int y)    
{    
    tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;    
    //cout<<x<<" "<<y<<endl;    
}    
void dfs(int x,int fa)    
{    
    deep[x]=deep[fa]+1; pos[x]=++sz; l[x]=sz;    
    for (int i=point[x];i;i=nxt[i]) {    
        if (v[i]==fa) continue;    
        dfs(v[i],x);    
    }    
    r[x]=sz;    
}    
void update(int x)    
{    
    int l=tr[x].l; int  r=tr[x].r;    
    for (int i=0;i<=1;i++)  {    
        if (l) tr[x].mx[i]=max(tr[x].mx[i],tr[l].mx[i]),tr[x].mn[i]=min(tr[x].mn[i],tr[l].mn[i]);    
        if (r) tr[x].mx[i]=max(tr[x].mx[i],tr[r].mx[i]),tr[x].mn[i]=min(tr[x].mn[i],tr[r].mn[i]);    
    }    
}    
int build(int l,int r,int d)    
{    
    cmpd=d;    
    int mid=(l+r)/2;    
    nth_element(tr+l,tr+mid,tr+r+1);    
    tr[mid].l=0; tr[mid].r=0; tr[mid].mark=0;    
    for (int i=0;i<=1;i++)     
     tr[mid].mx[i]=tr[mid].mn[i]=tr[mid].d[i];    
    if (l<mid) tr[mid].l=build(l,mid-1,d^1);    
    if (r>mid) tr[mid].r=build(mid+1,r,d^1);  
	//cout<<tr[mid].d[0]<<" "<<tr[tr[mid].l].d[0]<<" "<<tr[tr[mid].r].d[0]<<endl;  
    update(mid);    
    return mid;    
} 
bool check(int x)    
{    
    if (now.mn[1]<=tr[x].mn[1]&&tr[x].mx[1]<=now.mx[1]&&now.mn[0]<=tr[x].mn[0]&&tr[x].mx[0]<=now.mx[0]) return true;    
    return false;    
}   
bool find(int x)
{
    if (now.mn[1]>=tr[x].mn[1]&&now.mx[1]<=tr[x].mx[1]&&now.mn[0]>=tr[x].mn[0]&&now.mx[0]<=tr[x].mx[0]) return true;
	return false;	
}    
int query(int x)    
{ 
    if (tr[x].mark) {
          tr[tr[x].l].mark=tr[x].mark,tr[tr[x].r].mark=tr[x].mark;  
          tr[x].col=tr[x].mark; tr[x].mark=0;  
    }      
    if (now.d[0]==tr[x].d[0]) return tr[x].col;
    if (!tr[x].l&&!tr[x].r) return -1;
    int ans=-1;
    if (find(tr[x].l)&&tr[x].l) ans=query(tr[x].l);
    if (ans!=-1) return ans;
    if (find(tr[x].r)&&tr[x].r) ans=query(tr[x].r);
    return ans;
}    
bool pd(int x)    
{    
    int ans=0;
    for (int i=0;i<=1;i++) {   
	    bool mark=0; 
        if (tr[x].mn[i]<=now.mn[i]&&now.mn[i]<=tr[x].mx[i])  mark=true;    
        if (tr[x].mn[i]<=now.mx[i]&&now.mx[i]<=tr[x].mx[i])  mark=true;  
        if (now.mn[i]<=tr[x].mn[i]&&tr[x].mn[i]<=now.mx[i])  mark=true;
        if (now.mn[i]<=tr[x].mx[i]&&tr[x].mx[i]<=now.mx[i])  mark=true;
        ans+=mark;
    }    
    if (ans==2) return true;
	else return false;    
}    
void change(int x)    
{    
   if (check(x)) {    
     tr[x].mark=tr[x].col=now.col;
     return;    
   }    
   if (tr[x].mark) {
     tr[tr[x].l].mark=tr[x].mark,tr[tr[x].r].mark=tr[x].mark;  
     tr[x].col=tr[x].mark; tr[x].mark=0;  
    }
   if (now.mn[1]<=tr[x].d[1]&&tr[x].d[1]<=now.mx[1]&&now.mn[0]<=tr[x].d[0]&&tr[x].d[0]<=now.mx[0])    
    tr[x].col=now.col; 
   if (pd(tr[x].l)) 
     change(tr[x].l);    
   if (pd(tr[x].r)) 
     change(tr[x].r);    
}    
int main()    
{    
    freopen("a.in","r",stdin);    
    freopen("my.out","w",stdout);    
    scanf("%d",&T);    
    while (T--) {    
        tot=0;    
        memset(point,0,sizeof(point));    
        scanf("%d%d%d",&n,&c,&q);    
        for (int i=2;i<=n;i++) {    
            int x; scanf("%d",&x);    
            add(x,i);    
        }    
        sz=0; dfs(1,0);     
        //for (int i=1;i<=n;i++) cout<<pos[i]<<" "<<deep[i]<<" "<<l[i]<<" "<<r[i]<<endl;    
        for (int i=1;i<=n;i++) tr[i].d[0]=pos[i],tr[i].d[1]=deep[i],tr[i].col=1;    
        root=build(1,n,0);    
        LL ans=0;    
        for (int i=1;i<=q;i++) {    
            int x,l1,c; scanf("%d%d%d",&x,&l1,&c);    
            if (c==0)  {    
               now.d[0]=pos[x]; now.d[1]=deep[x];
			   now.mn[0]=pos[x]; now.mx[0]=pos[x];     
               now.mn[1]=deep[x]; now.mx[1]=deep[x];         
               int t=query(root); //cout<<t<<endl;    
               ans=(ans+(LL)i*t%p)%p;       
            }    
            else {    
                now.mn[0]=l[x]; now.mx[0]=r[x];     
                now.mn[1]=deep[x]; now.mx[1]=deep[x]+l1; now.col=c;    
                change(root);    
            }    
        }    
        printf("%I64d\n",ans);    
    }    
}    


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值