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

来源:互联网 发布:软件字体乱码 编辑:程序博客网 时间:2024/06/10 17:02

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);        }    }    


0 0
原创粉丝点击