[bzoj4154][Ipsc2015]Generating Synergy_KD-Tree_dfs序
Generating Synergy bzoj-4154 Ipsc-2015
题目大意:给定一棵n个节点树,m个操作,支持:将一个点周围所有距该点距离不超过l的子结点的颜色改成另一种颜色;查询单点颜色。每个点的颜色开始都是1。
注释:$1\le n,m\le 10^5$
想法:这就是一个典型的不是KD-Tree裸题,我们需要将它转化成点。
首先,我们先拉出整棵树的dfs序。
每个节点,我们设横坐标就是dfs序上的下标,纵坐标就是深度。我们发现,一个点的子树是一段连续的区间,然后当深度确定是,我们发现这就是矩阵赋值,加上pushdown操作即可。
单点查询遍历即可。不要忘记query的时候也要pushdown
另外没有插入操作,就不用重构了。
最后,附上丑陋的代码... ...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define N 100010 using namespace std; int head[N],to[N],nxt[N],cnt,deep[N],pos[N],last[N],tot,d,root; struct data { int p[2],mx[2],mn[2],c[2],w,tag; bool operator <( const data &a) const { return p[d]==a.p[d]?p[d^1]<a.p[d^1]:p[d]<a.p[d]; } }a[N]; inline void add( int x, int y) { to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt; } void dfs( int x) { int i; pos[x]=++tot,a[x].p[0]=pos[x],a[x].p[1]=deep[x]; for (i=head[x];i;i=nxt[i]) deep[to[i]]=deep[x]+1,dfs(to[i]); last[x]=tot; } inline void pushup( int x) { int l=a[x].c[0],r=a[x].c[1]; a[x].mx[0]=max(a[x].p[0],max(a[l].mx[0],a[r].mx[0])); a[x].mx[1]=max(a[x].p[1],max(a[l].mx[1],a[r].mx[1])); a[x].mn[0]=min(a[x].p[0],min(a[l].mn[0],a[r].mn[0])); a[x].mn[1]=min(a[x].p[1],min(a[l].mn[1],a[r].mn[1])); } int build( int l, int r, int now) { if (l>r) return 0; int mid=(l+r)>>1; d=now,nth_element(a+l,a+mid,a+r+1); a[mid].w=1,a[mid].tag=0; a[mid].c[0]=build(l,mid-1,now^1); a[mid].c[1]=build(mid+1,r,now^1); pushup(mid); return mid; } inline void pushdown( int x) { if (a[x].tag) { int l=a[x].c[0],r=a[x].c[1]; a[l].w=a[l].tag=a[r].w=a[r].tag=a[x].tag; a[x].tag=0; } } void update( int bx, int ex, int by, int ey, int v, int x) { if (!x||a[x].mx[0]<bx||a[x].mn[0]>ex||a[x].mx[1]<by||a[x].mn[1]>ey) return ; if (a[x].mn[0]>=bx&&a[x].mx[0]<=ex&&a[x].mn[1]>=by&&a[x].mx[1]<=ey) { a[x].w=a[x].tag=v; return ; } pushdown(x); if (a[x].p[0]>=bx&&a[x].p[0]<=ex&&a[x].p[1]>=by&&a[x].p[1]<=ey)a[x].w=v; update(bx,ex,by,ey,v,a[x].c[0]),update(bx,ex,by,ey,v,a[x].c[1]); } int query( int px, int py, int x) { d^=1; if (a[x].p[0]==px&&a[x].p[1]==py) return a[x].w; pushdown(x); if (d) { if (py<a[x].p[1]||(py==a[x].p[1]&&px<a[x].p[0])) return query(px,py,a[x].c[0]); else return query(px,py,a[x].c[1]); } else { if (px<a[x].p[0]||(px==a[x].p[0]&&py<a[x].p[1])) return query(px,py,a[x].c[0]); else return query(px,py,a[x].c[1]); } } int main() { int T; scanf ( "%d" ,&T); while (T--) { memset (head,0, sizeof (head)),cnt=1; a[0].mx[0]=a[0].mx[1]=-1<<30,a[0].mn[0]=a[0].mn[1]=1<<30; int n,m,i,x,y,z,ans=0; scanf ( "%d%*d%d" ,&n,&m); for (i=2;i<=n;i++) scanf ( "%d" ,&x),add(x,i); dfs(1); root=build(1,n,0); for (i=1;i<=m;i++) { scanf ( "%d%d%d" ,&x,&y,&z); if (z) update(pos[x],last[x],deep[x],deep[x]+y,z,root); else d=1,ans=(ans+( long long )query(pos[x],deep[x],root)*i)%1000000007; } printf ( "%d\n" ,ans); } return 0; } |
小结:KD-Tree这种题还是挺好玩的..
| 欢迎来原网站坐坐! >原文链接<
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步