bzoj3730 震波 [动态点分治,树状数组]
思路
如果没有强制在线的话可以离线之后CDQ分治随便搞。
有了强制在线之后……可能可以二维线段树?然而我不会算空间。
然后我们莫名其妙地想到了动态点分治,然后这题就差不多做完了。
点分树有一个重要的性质:若\(x,y\)在点分树上的\(lca\)是\(w\),那么在原树上\(w\)也在\(x\rightarrow y\)的路径上。
我们可以在点分树上枚举\(lca\),算一下这个\(lca\)统领的连通块对\(x\)有多少贡献,减去\(x\)所在的连通块贡献,就ok了。
贡献可以用树状数组或动态开点线段树维护。普通树状数组的空间复杂度\(O(n^2)\),但每一个\(x\)开的树状数组可以只开到\(size_x\)的大小,复杂度就降为\(O(n\log n)\)了。
还有一题“烁烁的游戏”和这题差不多,但那题支持离线,也许有其他做法。
代码
辣鸡bzoj没有c++11差评QwQ
#include<bits/stdc++.h>
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define sz 101001
typedef long long ll;
typedef double db;
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
// template<typename T>inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
// template<typename T>inline void read(T& t)
// {
// t=0;char f=0,ch=getchar();double d=0.1;
// while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
// while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
// if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
// t=(f?-t:t);
// }
// template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
template<typename T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
template<typename T>inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
// void file()
// {
// #ifndef ONLINE_JUDGE
// freopen("a.txt","r",stdin);
// #endif
// }
// #ifdef mod
// ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
// ll inv(ll x){return ksm(x,mod-2);}
// #else
// ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
// #endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
int n,m;
int a[sz],w[sz];
struct hh{int t,nxt;}edge[sz<<1];
int head[sz],ecnt;
void make_edge(int f,int t)
{
edge[++ecnt]=(hh){t,head[f]};
head[f]=ecnt;
edge[++ecnt]=(hh){f,head[t]};
head[t]=ecnt;
}
int sum,size[sz],root,mn;
bool vis[sz];
#define v edge[i].t
void findroot(int x,int fa)
{
size[x]=1;
int S=-1;
go(x) if (v!=fa&&!vis[v])
{
findroot(v,x);
size[x]+=size[v];
chkmax(S,size[v]);
}
chkmax(S,sum-size[x]);
if (chkmin(mn,S)) root=x;
}
int dep[sz]; // x在点分树上的深度
int fa[sz][30]; // x在点分树上到根的链上dep=i的祖先(特别地,fa[x][dep[x]]=x)
int dis[sz][30]; // x到fa[x][i]的距离(特别地,dis[x][dep[x]]=0)
vector<int>tr1[sz],tr2[sz];
// tr1[x]:x所统领的连通块里以到x的距离为关键字的树状数组
// tr2[x]:x所统领的连通块里以到fa[x][1]的距离为关键字的树状数组
void calc(int x,int f,int rt,int d)
{
++dep[x];fa[x][dep[x]]=rt;dis[x][dep[x]]=d;
go(x) if (v!=f&&!vis[v]) calc(v,x,rt,d+1);
}
void build(int x)
{
vis[x]=1;
int all=sum;tr1[x].resize(all+5);
calc(x,0,x,0);
go(x) if (!vis[v])
{
mn=1e9;
sum=size[v];if (sum>size[x]) sum=all-size[x];
findroot(v,0);
tr2[root].resize(sum+5);
build(root);
}
}
#undef v
void add1(int x,int p,int w){++p;while (p<(int)tr1[x].size()) tr1[x][p]+=w,p+=(p&(-p));}
int query1(int x,int p)
{
++p;
if (p<=0) return 0;
chkmin(p,(int)tr1[x].size()-1);
int ret=0;
while (p) ret+=tr1[x][p],p-=(p&(-p));
return ret;
}
void add2(int x,int p,int w){++p;while (p<(int)tr2[x].size()) tr2[x][p]+=w,p+=(p&(-p));}
int query2(int x,int p)
{
++p;
if (p<=0) return 0;
chkmin(p,(int)tr2[x].size()-1);
int ret=0;
while (p) ret+=tr2[x][p],p-=(p&(-p));
return ret;
}
void add(int x,int w)
{
::w[x]+=w;
drep(i,dep[x],2)
add1(fa[x][i],dis[x][i],w),
add2(fa[x][i],dis[x][i-1],w);
add1(fa[x][1],dis[x][1],w);
}
int query(int x,int d)
{
int ret=query1(x,d);
drep(i,dep[x]-1,1) ret+=query1(fa[x][i],d-dis[x][i])-query2(fa[x][i+1],d-dis[x][i]);
return ret;
}
int main()
{
// file();
scanf("%d %d",&n,&m);
rep(i,1,n) scanf("%d",&a[i]);
int x,y,z;
rep(i,1,n-1) scanf("%d %d",&x,&y),make_edge(x,y);
sum=n;mn=1e9;findroot(1,0);
build(root);
rep(i,1,n) add(i,a[i]);
int lastans=0;
while (m--)
{
scanf("%d %d %d",&z,&x,&y);x^=lastans;y^=lastans;
if (z==0) printf("%d\n",lastans=query(x,y));
else add(x,y-w[x]);
}
return 0;
}
bzoj3730 震波 [动态点分治,树状数组]的更多相关文章
- 【BZOJ-3730】震波 动态点分治 + 树状数组
3730: 震波 Time Limit: 15 Sec Memory Limit: 256 MBSubmit: 626 Solved: 149[Submit][Status][Discuss] D ...
- bzoj 3730 震波——动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3730 查询一个点可以转化为查询点分树上自己到根的路径上每个点对应范围答案.可用树状数组 f ...
- bzoj 3730 震波 —— 动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3730 建点分树,每个点记两个树状数组,存它作为重心管辖的范围内,所有点到它的距离情况和到它在 ...
- HDU 4918 Query on the subtree(动态点分治+树状数组)
题意 给定一棵 \(n\) 个节点的树,每个节点有点权.完成 \(q\) 个操作--操作分两种:修改点 \(x\) 的点权.查询与 \(x\) 距离小于等于 \(d\) 的权值总和. \(1 \leq ...
- bzoj 4372 烁烁的游戏——动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 和 bzoj 3070 震波 是一个套路.注意区间修改的话,树状数组不能表示 dis ...
- bzoj 4372 烁烁的游戏 —— 动态点分治+树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4372 本以为和 bzoj3730 一样,可以直接双倍经验了: 但要注意一下,树状数组不能查询 ...
- luogu 5311 [Ynoi2011]D1T3 动态点分治+树状数组
我这份代码已经奇怪到一定程度了~ 洛谷上一直 $TLE$,但是本地造了几个数据都过了. 简单说一下题解: 先建出来点分树. 对于每一个询问,在点分树中尽可能向上跳祖先,看是否能够处理这个询问. 找到最 ...
- BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组
BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一 ...
- BZOJ 2683 简单题 cdq分治+树状数组
题意:链接 **方法:**cdq分治+树状数组 解析: 首先对于这道题,看了范围之后.二维的数据结构是显然不能过的.于是我们可能会考虑把一维排序之后还有一位上数据结构什么的,然而cdq分治却可以非常好 ...
- BZOJ_3262_陌上花开_CDQ分治+树状数组
BZOJ_3262_陌上花开_CDQ分治+树状数组 Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),用三个整数表示. 现在要对每朵花评级,一朵花的级别是它拥有的 ...
随机推荐
- 一次enq: TX - index contention等待事件处理
收到告警短信: BOMC一般告警,告警2次,最后告警时间:03-03 22:21,监控对象:/XX系统/数据库/ORACLE数据库/XXX.XX.XX.XX*XXXDB_LE_DBS/ORACLE实例 ...
- 24.join算法/锁_1
一. JOIN算法1.1. JOIN 语法 mysql> select * from t4; +---+------+ | a | b | +---+------+ | | 11 | | | 5 ...
- [译]C#7 Pattern Matching
原文 public struct Square { public double Side { get; } public Square(double side) { Side = side; } } ...
- springboot11-01-security入门
场景: 有3个页面:首页.登录页.登录成功后的主页面,如下图: 如果没有登录,点击“去主页”,会跳转到登录页 如果已经登录,点击“去主页”,跳转到主页,显示“hello 用户名” 下面用springb ...
- 测试四则运算2:Right-BICEP
n6个值得测试的具体部位,他们能够提高你的测试技巧 nRight-结果是否正确? nB-是否所有的边界条件都是正确的? nI-能查一下反向关联吗 nC-能用其他手段交叉检查一下结果吗? nE-你是否可 ...
- 剑指offer: 数组中的逆序对
1. 最简单的思路,对每个值,遍历与其逆序的数组对:但时间复杂度太高: 2. 归并排序的思路: 先将数组分隔成子数组,先统计出子数组内的逆序对的数目,然后统计两个相邻子数组之间的逆序对的数目: int ...
- ue4 蓝图方法备份
normalized 标准化 向量标准化 +- 1,1,1 内的值 角度标准化 +-180内的值 delta A-B (输出时roll在后面) 角度相减 interp 插值运算 (做平滑移动常用) ...
- Fragment处理接口回调,网络请求数据
03-06 19:57:46.138 8691-8691/com.retech.myapplication E/glz: onAttach03-06 19:57:46.138 8691-8691/co ...
- DEX、ODEX、OAT文件&Dalvik和ART虚拟机
https://www.jianshu.com/p/389911e2cdfb https://www.jianshu.com/p/a468e714aca7 ODEX是安卓上的应用程序apk中提取出来的 ...
- linux 制作U盘启动,和定制系统
找到u盘的路径 fdisk -l 将镜像写入u盘 dd if=/root/Downloads/kali-linux-2017.1-amd64.iso of=/dev/sdc 定制U盘启动系统: 安装完 ...