我这份代码已经奇怪到一定程度了~

洛谷上一直 $TLE$,但是本地造了几个数据都过了.

简单说一下题解:

先建出来点分树.
对于每一个询问,在点分树中尽可能向上跳祖先,看是否能够处理这个询问.
找到最高点的好处就是该点的询问可以全部由那个祖先来统计.
因为祖先到 $x$ 是合法的,而那个祖先会统计子树里所有的点,当然也包括 $x$ 的所有子树.
假设现在枚举到点 $x$ ,并处理 $x$ 上面的所有询问.
$x$ 子树中的每一个点都可以用一个三元组来表示:$(l,r,c)$ 代表该点到 $x$ 路径的值域在 $[l,r],$颜色为 $c.$
那么对于一个询问,就是查询所有在 $[l_{q},r_{q}]$ 中 $c$ 的不同种类.
我们先将 $l$ 从大到小排序,依次处理点和询问.
如果有多个点,那么显然 $r$ 小的优先级会更高,即后加入的同颜色的点如果 $r$ 更小就直接替换.
这么做就能保证所有颜色的点在当前局面只出现一次.
现在的问题就是统计 $(l,r,l,r)$ 这个矩形内点的数量.
对于这个问题,可以用 $O(logn)$ 的树状数组来进行数点,总时间复杂度为 $O(nlog^2n)$.

Code:

#include <bits/stdc++.h>
#define N 1000005
#define inf 100001
#define setIO(s) freopen(s".in","r",stdin) ,freopen(s".out","w",stdout)
using namespace std;
int edges,n,flag;
int hd[N],to[N<<1],nex[N<<1],val[N],rt[N<<2];
void add(int u,int v)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
namespace BIT
{
int C[N];
int lowbit(int t)
{
return t&(-t);
}
void update(int x,int v)
{
for(;x<N;x+=lowbit(x)) C[x]+=v;
}
int query(int x)
{
int re=0;
for(;x>0;x-=lowbit(x)) re+=C[x];
return re;
}
void re(int x)
{
for(;x<N;x+=lowbit(x)) C[x]=0;
}
};
struct Node
{
int l,r,x;
Node(int l=0,int r=0,int x=0):l(l),r(r),x(x){}
};
vector<Node>e[N];
struct Point
{
int l,r,id,val;
Point(int l=0,int r=0,int id=0,int val=0):l(l),r(r),id(id),val(val){}
};
vector<Point>F[N];
bool cmp(Point a,Point b)
{
return a.l==b.l?a.id>b.id:a.l>b.l;
}
int root,sn;
int mx[N],size[N],vis[N],Fa[N],answer[N],lsty[N],lstx[N];
void dfs(int u,int ff)
{
size[u]=1;
for(int i=hd[u];i;i=nex[i])
if(to[i]!=ff&&!vis[to[i]])
dfs(to[i],u),size[u]+=size[to[i]];
}
void getroot(int u,int ff)
{
size[u]=1,mx[u]=0;
for(int i=hd[u];i;i=nex[i])
if(to[i]!=ff&&!vis[to[i]])
getroot(to[i],u),size[u]+=size[to[i]],mx[u]=max(mx[u],size[to[i]]);
mx[u]=max(mx[u],sn-size[u]);
if(mx[u]<mx[root]) root=u;
}
void calc(int u,int ff,int Min,int Max,int rt)
{
Min=min(Min,u),Max=max(Max,u);
F[rt].push_back(Point(Min,Max,u,val[u])), e[u].push_back(Node(Min,Max,rt));
for(int i=hd[u];i;i=nex[i])
if(!vis[to[i]]&&to[i]!=ff)
calc(to[i],u,Min,Max,rt);
}
void prepare(int u)
{
vis[u]=1;
calc(u,0,u,u,u);
for(int i=hd[u];i;i=nex[i])
if(!vis[to[i]])
dfs(to[i],u),sn=size[to[i]],root=0,getroot(to[i],u),Fa[root]=u,prepare(root);
}
void Push(int u,int l,int r,int id)
{
for(int i=0;i<(int)e[u].size();++i)
{
if(e[u][i].l>=l&&e[u][i].r<=r)
{
F[e[u][i].x].push_back(Point(l,r,-1,id));
break;
}
}
}
void solve(int u)
{
int i,j;
sort(F[u].begin(),F[u].end(),cmp);
for(i=0;i<(int)F[u].size();++i)
{
Point p=F[u][i];
if(p.id==-1)
answer[p.val]=BIT::query(p.r);
else
{
if(!lsty[p.val]||p.r<=lsty[p.val])
{
if(lsty[p.val])
{
BIT::update(lsty[p.val],-1);
}
BIT::update(p.r,1);
lstx[p.val]=p.l, lsty[p.val]=p.r;
}
}
}
for(i=0;i<(int)F[u].size();++i)
if(F[u][i].id!=-1)
{
if(lsty[F[u][i].val]) BIT::re(lsty[F[u][i].val]);
lstx[F[u][i].val]=lsty[F[u][i].val]=0;
}
}
int main()
{
int i,j,m;
// setIO("input");
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i) scanf("%d",&val[i]);
for(i=1;i<n;++i)
{
int x,y;
scanf("%d%d",&x,&y),add(x,y),add(y,x);
}
root=0,mx[0]=sn=n,getroot(1,0),prepare(root);
for(i=1;i<=m;++i)
{
int l,r,x;
scanf("%d%d%d",&l,&r,&x),Push(x,l,r,i);
}
for(i=1;i<=n;++i) if(F[i].size()) solve(i);
for(i=1;i<=m;++i) printf("%d\n",answer[i]);
return 0;
}

  

  

luogu 5311 [Ynoi2011]D1T3 动态点分治+树状数组的更多相关文章

  1. HDU 4918 Query on the subtree(动态点分治+树状数组)

    题意 给定一棵 \(n\) 个节点的树,每个节点有点权.完成 \(q\) 个操作--操作分两种:修改点 \(x\) 的点权.查询与 \(x\) 距离小于等于 \(d\) 的权值总和. \(1 \leq ...

  2. 【BZOJ-3730】震波 动态点分治 + 树状数组

    3730: 震波 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 626  Solved: 149[Submit][Status][Discuss] D ...

  3. bzoj 4372 烁烁的游戏——动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 和 bzoj 3070 震波 是一个套路.注意区间修改的话,树状数组不能表示 dis ...

  4. bzoj 3730 震波——动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3730 查询一个点可以转化为查询点分树上自己到根的路径上每个点对应范围答案.可用树状数组 f ...

  5. bzoj 4372 烁烁的游戏 —— 动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 本以为和 bzoj3730 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...

  6. bzoj 3730 震波 —— 动态点分治+树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3730 建点分树,每个点记两个树状数组,存它作为重心管辖的范围内,所有点到它的距离情况和到它在 ...

  7. BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组

    BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一 ...

  8. [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)

    [BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...

  9. BZOJ 2683 简单题 cdq分治+树状数组

    题意:链接 **方法:**cdq分治+树状数组 解析: 首先对于这道题,看了范围之后.二维的数据结构是显然不能过的.于是我们可能会考虑把一维排序之后还有一位上数据结构什么的,然而cdq分治却可以非常好 ...

随机推荐

  1. [c++] 用宏定义一个函数

    要点:变量都用括号括起来,防止出错,结尾不需要;.在实际编程中,不推荐把复杂的函数使用宏,不容易调试.多行用\ 要写好C语言,漂亮的宏定义是非常重要的.宏定义可以帮助我们防止出错,提高代码的可移植性和 ...

  2. 喝奶茶最大值(不能喝自己班级的)2019 Multi-University Training Contest 8--hdu杭电第8场(Roundgod and Milk Tea)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6667 题意: 有 n个班级,每个班级有a个人.b个奶茶,每个班的人不能喝自己的奶茶,只能喝别人班的奶茶 ...

  3. python PEP8常用规范(看完你会感谢我的!)

    完整的规范移步传送门 pep8规范 官方文档:[https://www.python.org/dev/peps/pep-0008/](https://www.python.org/dev/peps/p ...

  4. SpringMVC实现全局异常处理器 (转)

    出处:  SpringMVC实现全局异常处理器 我们知道,系统中异常包括:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发.测试通过手 ...

  5. 为什么说Python采用的是基于值的内存管理模式?

    Python中的变量并不直接存储值,而是存储了值的内存地址或者引用,假如为不同变量赋值为相同值,这个值在内存中只有一份,多个变量指向同一块内存地址.

  6. redis 学习(二)-- 通用命令

    redis 学习(二)-- 通用命令 1. keys pattern 含义:查找所有符合给定模式(pattern)的key 命令 含义 keys * 遍历所有 key keys he[h-l]* 遍历 ...

  7. 定制ListView的界面(让列表中不仅有文字还有图片fruitImage.setImageResource(fruit.getImageId());)

    1.定义自己的实体类来作为ListView的适配类型如: public class Fruit { private String name;//水果的名字 private int imageId;// ...

  8. 098、Swarm 如何实现 Failover (Swarm05)

    参考https://www.cnblogs.com/CloudMan6/p/7898245.html   故障是在所难免的,容器可能崩溃,Docker Host 可能宕机,不过幸运的是,Swarm 已 ...

  9. MySQL 主从同步架构中你不知道的“坑”(2)

    指定同步库情况 1.binlog_format= ROW模式‍ mysql> use testdb; Database changed mysql> show tables; +----- ...

  10. Python新式类与经典类(旧式类)的区别

    看写poc的时候看到的,思考了半天,现在解决了 转载自http://blog.csdn.net/zimou5581/article/details/53053775 Python中类分两种:旧式类和新 ...