zoukankan      html  css  js  c++  java
  • [bzoj4154][Ipsc2015]Generating Synergy_KD-Tree_dfs序

    Generating Synergy bzoj-4154 Ipsc-2015

    题目大意:给定一棵n个节点树,m个操作,支持:将一个点周围所有距该点距离不超过l的子结点的颜色改成另一种颜色;查询单点颜色。每个点的颜色开始都是1。

    注释:$1le n,mle 10^5$


    想法:这就是一个典型的不是KD-Tree裸题,我们需要将它转化成点。

    首先,我们先拉出整棵树的dfs序。

    每个节点,我们设横坐标就是dfs序上的下标,纵坐标就是深度。我们发现,一个点的子树是一段连续的区间,然后当深度确定是,我们发现这就是矩阵赋值,加上pushdown操作即可。

    单点查询遍历即可。不要忘记query的时候也要pushdown

    另外没有插入操作,就不用重构了。

    最后,附上丑陋的代码... ...

    #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
    ",ans);
    	}
    	return 0;
    }
    

    小结:KD-Tree这种题还是挺好玩的..

  • 相关阅读:
    跃迁方法论 Continuous practice
    EPI online zoom session 面试算法基础知识直播分享
    台州 OJ 2648 小希的迷宫
    洛谷 P1074 靶形数独
    洛谷 P1433 DP 状态压缩
    台州 OJ FatMouse and Cheese 深搜 记忆化搜索
    台州 OJ 2676 Tree of Tree 树状 DP
    台州 OJ 2537 Charlie's Change 多重背包 二进制优化 路径记录
    台州 OJ 2378 Tug of War
    台州 OJ 2850 Key Task BFS
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9393184.html
Copyright © 2011-2022 走看看