您的位置:首页 > 其它

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

2017-03-17 08:44 441 查看

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
,point
,v
,deep
,l
,r
,pos
,sz,root,T,c;
struct data{
int d[2],mx[2],mn[2];
int l,r,mark,col;
}now,tr
;
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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: