题意

分析

引用PoPoQQQ的话

吾辈有生之年终于把这道题切了。。。QAQ

(蒟蒻狂笑)

Orz PoPoQQQ,我又抄PoPoQQQ的题解了 …

  • 突然发现有旋Treap没那么难写
  • 学习了一波C++语法,第一次用指针,什么new/deletenew/deletenew/delete也大概会用了…(这玩意还能重载…跪了)
  • 学习了一波点分治的正确写法.我之前写的都是什么烂玩意儿
  • dalao代码的细节处理得好啊,学习了学习了 (这就是你抄代码的原因?)

这种符合某条件的点对,首先就想到点分治…先假设树的形态是固定的,我们考虑满足dis(i,j)<=ri+rjdis(i,j)<=r_i+r_jdis(i,j)<=ri​+rj​的点对,假设它们在点分树上的lcalcalca为uuu,定义did_idi​为iii到uuu的距离.那么有di+dj<=ri+rjdi−ri<=rj−djd_i+d_j<=r_i+r_j\\d_i-r_i<=r_j-d_jdi​+dj​<=ri​+rj​di​−ri​<=rj​−dj​ 那么我们将子树中所有di−rid_i-r_idi​−ri​插入平衡树,只需要查询rj−djr_j-d_jrj​−dj​在平衡树中的排名就能查询和jjj组成点对的iii的数量.

由于树的形态不确定,那么就动态点分治就行了.那么我们像点分治常见的套路,在点分树上的每一个点维护两颗平衡树,一棵ttt表示子树内的所有点di−rid_i-r_idi​−ri​组成的平衡树,一棵tftftf维护这一棵子树对父亲的贡献.那么查询一个点的时候,从那个点往上计算,每一次用父亲的ttt所查询的值减去这棵子树的tftftf所查询的值 就能不重不漏地算出答案(因为要去除点对在同一棵子树内的情况).然后修改可以和查询在同一个函数内进行,先查后修改.

由于动态点分治可能会出现一条链的情况,那么要像替罪羊树的思想,子树不平衡就重构…

用setsetset存边挺省事的,就是比较慢…

CODE

手写rand真快 … 要更详细的代码注释去PoPoQQQ

#include <set>
#include <queue>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
template<class T>inline void read(T &res) {
char ch; int flg = 1; for(;!isdigit(ch=getchar());)if(ch=='-')flg=-flg;
for(res=ch-'0';isdigit(ch=getchar());res=res*10+ch-'0'); res*=flg;
}
typedef long long LL;
const int MAXN = 100100;
const int mod = 1e9; int n, r[MAXN];
LL lastans; int Rand() { //手写rand(qwq)
static int G = 3;
return G = 3ll * G % 998244353;
} namespace Gragh { struct edge { int to, nxt, len, ban; }e[MAXN<<1];
int fir[MAXN], cnt = 1, f[MAXN][17], dep[MAXN], dis[MAXN]; inline void Add(int u, int v, int w) {
e[++cnt] = (edge) { v, fir[u], w, -1 }, fir[u] = cnt;
} inline void Build_LCA(int i) {
for(int j = 1; j < 17; ++j)
f[i][j] = f[f[i][j-1]][j-1];
} inline int LCA(int u, int v) {
if(dep[u] < dep[v]) swap(u, v);
for(int i = 16; ~i; --i)
if((dep[u]-dep[v])&(1<<i)) u = f[u][i];
if(u == v) return u;
for(int i = 16; ~i; --i)
if(f[u][i] != f[v][i])
u = f[u][i], v = f[v][i];
return f[u][0];
} inline int Dist(int u, int v) {
return dis[u] + dis[v] - (dis[LCA(u, v)]<<1);
} } struct Treap { static queue<Treap*> bin; Treap *ls, *rs;
int val, key, cnt, size; inline void* operator new (size_t, int _) {
Treap *re;
if(bin.size()) re = bin.front(), bin.pop();
else {
static Treap *mempool, *C; //static相当于表示全局变量
if(C == mempool) mempool = (C = new Treap[1<<16])+(1<<16); //内存不够就又开多点
re = C++;
}
re->ls = re->rs = 0x0;
re->val = _;
re->key = Rand();
re->cnt = re->size = 1;
return re;
} inline void operator delete (void *p) {
bin.push((Treap*)p); //重载delete 回收利用
} inline void Push_Up() {
size = cnt;
if(ls) size += ls->size;
if(rs) size += rs->size;
} inline friend void Zig(Treap *&x) {
Treap *y = x->ls;
x->ls = y->rs;
y->rs = x; x = y;
x->rs->Push_Up();
x->Push_Up();
} inline friend void Zag(Treap *&x) {
Treap *y = x->rs;
x->rs = y->ls;
y->ls = x; x = y;
x->ls->Push_Up();
x->Push_Up();
} friend void Insert(Treap *&x, int y) { //插入进Treap
if(!x) { x = new(y) Treap; return; }
if(y == x->val) x->cnt++;
else if(y < x->val) {
Insert(x->ls, y);
if(x->ls->key > x->key)
Zig(x);
}
else {
Insert(x->rs, y);
if(x->rs->key > x->key)
Zag(x);
}
x->Push_Up();
} friend void Delete(Treap *&x) { //删除以x为根的Treap子树
if(!x) return;
Delete(x->ls);
Delete(x->rs);
delete x; x = 0x0;
} friend int Query(Treap *x, int y) {
if(!x) return 0;
if(y < x->val) return Query(x->ls, y);
else return (x->ls ? x->ls->size : 0) + x->cnt + Query(x->rs, y);
} }; queue<Treap*> Treap::bin; //声明一下才能用 namespace Dynamic_TDC { using namespace Gragh; //在namespace里using别的namespace...
#define alpha 0.88
#define Sit set<int>::iterator int fa[MAXN], v[MAXN], cur; Treap *t[MAXN], *tf[MAXN]; set<int> to[MAXN]; void Del(int x) { //删除x为根的子树
v[x] = cur;
for(Sit it = to[x].begin(); it != to[x].end(); ++it)
Del(*it), Delete(tf[*it]);
to[x].clear();
Delete(t[x]);
} int Get_Size(int x, int ff) { //求SIZE
int re = 1;
for(int i = fir[x]; i; i = e[i].nxt)
if(v[e[i].to] == cur && e[i].ban != cur && e[i].to != ff)
re += Get_Size(e[i].to, x);
return re;
} int Get_G(int x, int ff, int Size, int &cg) { //求重心
int re = 1; bool flag = 1;
for(int i = fir[x]; i; i = e[i].nxt)
if(v[e[i].to] == cur && e[i].ban != cur && e[i].to != ff) {
int temp = Get_G(e[i].to, x, Size, cg);
if(temp<<1 > Size) flag = 0;
re += temp;
}
if((Size-re)<<1 > Size) flag = 0;
if(flag) cg = x; return re;
} void DFS(int x, int ff, int dpt, Treap *&p) { //将子树内的点全部插入Treap
Insert(p, dpt-r[x]);
for(int i = fir[x]; i; i = e[i].nxt)
if(v[e[i].to] == cur && e[i].ban != cur && e[i].to != ff)
DFS(e[i].to, x, dpt+e[i].len, p);
} int TDC(int x) { //点分治
int Size = Get_Size(x, 0);
Get_G(x, 0, Size, x);
DFS(x, 0, 0, t[x]);
for(int i = fir[x]; i; i = e[i].nxt)
if(v[e[i].to] == cur && e[i].ban != cur) {
Treap *p = 0x0;
DFS(e[i].to, x, e[i].len, p); //统计子树对父亲x的贡献
e[i].ban = e[i^1].ban = cur; //打上不能再访问的标记
int temp = TDC(e[i].to);
tf[temp] = p; fa[temp] = x; to[x].insert(temp);
}
return x;
} inline void Re_build(int x) { //重建
++cur; Del(x); int y = fa[x];
Treap *p = tf[x]; tf[x] = 0x0;
int temp = TDC(x);
fa[temp] = y;
if(y) to[y].erase(x), to[y].insert(temp); //先删边再加边
tf[temp] = p;
} inline void Insert(int x) { //插入点分树
for(int i = x; i; i = fa[i]) {
if(fa[i]) {
int d = Dist(x, fa[i]);
lastans += Query(t[fa[i]], r[x]-d);
lastans -= Query(tf[i], r[x]-d);
Insert(tf[i], d-r[x]);
}
int D = Dist(x, i);
Insert(t[i], D-r[x]);
} int temp = 0;//替罪咩重建
for(int i = x; fa[i]; i = fa[i])
if((double)t[i]->size / t[fa[i]]->size > alpha)
temp = fa[i];
if(temp) Re_build(temp);
} } int main () {
read(n), read(n);
int x, y;
for(int i = 1; i <= n; ++i) {
read(x), read(y), read(r[i]);
x ^= (lastans % mod);
Gragh::Add(i, x, y);
Gragh::Add(x, i, y);
Gragh::f[i][0] = x;
Gragh::dep[i] = Gragh::dep[x] + 1;
Gragh::dis[i] = Gragh::dis[x] + y;
Gragh::Build_LCA(i); //预处理倍增 Dynamic_TDC::to[x].insert(i);
Dynamic_TDC::fa[i] = x;
Dynamic_TDC::Insert(i); printf("%lld\n", lastans);
}
}

看着250行抄来的代码陷入沉思

BZOJ 3435 / Luogu 3920 [WC2014]紫荆花之恋 (替罪羊树 动态点分治 套 Treap)的更多相关文章

  1. bzoj 3435: [Wc2014]紫荆花之恋 替罪羊树维护点分治 && AC400

    3435: [Wc2014]紫荆花之恋 Time Limit: 240 Sec  Memory Limit: 512 MBSubmit: 159  Solved: 40[Submit][Status] ...

  2. BZOJ3435: [Wc2014]紫荆花之恋(替罪羊树,Treap)

    Description 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是 ...

  3. luogu P3920 [WC2014]紫荆花之恋

    LINK:紫荆花之恋 每次动态加入一个节点 统计 有多少个节点和当前节点的距离小于他们的权值和. 显然我们不能n^2暴力. 考虑一个简化版的问题 树已经给出 每次求某个节点和其他节点的贡献. 不难想到 ...

  4. BZOJ 3435: [Wc2014]紫荆花之恋

    二次联通门 : BZOJ 3435: [Wc2014]紫荆花之恋 二次联通门 : luogu P3920 [WC2014]紫荆花之恋 /* luogu P3920 [WC2014]紫荆花之恋 怀疑人生 ...

  5. 【BZOJ3435】[Wc2014]紫荆花之恋 替罪点分树+SBT

    [BZOJ3435][Wc2014]紫荆花之恋 Description 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从 ...

  6. BZOJ3435 & 洛谷3920 & UOJ55:[WC2014]紫荆花之恋

    https://www.lydsy.com/JudgeOnline/problem.php?id=3435 https://www.luogu.org/problemnew/show/P3920 ht ...

  7. BZOJ3435[Wc2014]紫荆花之恋——动态点分治(替罪羊式点分树套替罪羊树)

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...

  8. [WC2014]紫荆花之恋(动态点分治+替罪羊思想)

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...

  9. UOJ#55 [WC2014]紫荆花之恋

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这个大树实际上是一个带权树. ...

随机推荐

  1. mysql导入数据报错:Incorrect datetime value

    incorrect datetime value 报错信息如下图: 意思很明显是说,'0000-00-00 00:00:00'不是一个有效的日期类型的值 解决办法: sql_mode 中删除 NO_Z ...

  2. (八)动态 sql

    目录 什么是动态 sql sql 片段 foreach 标签 什么是动态 sql 我们之前在映射文件中,配置 sql 的时候,其实都是静态的 : <!--复杂查询--> <selec ...

  3. 为什么我们需要Pod?(容器设计模式sidecar)

    Pod,是 Kubernetes 项目中最小的 API 对象 容器的本质是进程,就是未来云计算系统中的进程:容器镜像就是这个系统里的".exe"安装包 Kubernetes 就是操 ...

  4. Flask 卡住, 无响应问题

    自己学习Flask+Gevent, 做了一个小接口服务器, 但在收到请求后, 打印请求的报文, 并返回正确格式, 运行后会出现收到请求消息后,Flask卡住无响应的的问题, 有时候点击ctrl+C才能 ...

  5. nginx反向代理服务器以及负载均衡,从安装到配置

    nginx的具体作用不用细说,很强大,做负载均衡.反向代理服务器解决前端跨域问题等等.下面是nginx的安装过程 首先nginx主要的依赖: pcre. pcre-devel zlib zlib-de ...

  6. Spring 自定义Bean 实例获取

    一.通过指定配置文件获取, 对于Web程序而言,我们启动spring容器是通过在web.xml文件中配置,这样相当于加载了两次spring容器 ApplicationContext ac = new ...

  7. [NOIP10.5模拟赛]1.a题解--离散化+异或线段树

    题目链接: 咕咕咕 https://www.luogu.org/problemnew/show/CF817F 闲扯 在Yali经历几天折磨后信心摧残,T1数据结构裸题考场上连暴力都TM没打满 分析 观 ...

  8. 3. Java开发环境的搭建:安装JDK,配置环境变量

    1.安装JDK开发环境 下载网站:http://www.oracle.com/ 开始安装JDK: 修改安装目录如下: 确定之后,单击“下一步”. 注:当提示安装JRE时,可以选择不要安装. 2.配置环 ...

  9. Dubbo相关的基础

    Dubbo是一款高性能轻量级的java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务注册与发现. Dubbo是阿里开源的一个项目,现在已经是Apache的顶级 ...

  10. Oracle---PL/SQL的学习

    PL/SQL程序 一.定义 declare 说明部分 begin 语句序列(DML语句) exception 例外处理语句 end; 二. 变量和常量说明 a) 说明变量(char,varchar2, ...