标签:解密 odi ons ack vector math 需要 build 树状数组
在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
为了体现程序的在线性,操作中的x、y、k都需要异或你程序上一次的输出来解密,如果之前没有输出,则默认上一次的输出为0。
第一行包含两个正整数N和M。
第二行包含N个正整数,第i个数表示value[i]。
接下来N-1行,每行包含两个正整数u、v,表示u和v之间有一条无向边。
接下来M行,每行包含三个数,表示M次操作。
包含若干行,对于每个询问输出一行一个正整数表示答案。
8 1
1 10 100 1000 10000 100000 1000000 10000000
1 2
1 3
2 4
2 5
3 6
3 7
3 8
0 3 1
11100101
点分树套树状数组。
先建出点分树,对于每个分治块建一颗树状数组;对于每个分治块的重心,每个儿子的子树也建一颗树状数组。
树状数组以\(dep\)为下标,记的是权值之和。
那么对于修改点权,一共有\(O(\log n)\)个分治块和它相交,在树状数组上修改下就好了。
对于询问也差不多,暴力枚举每个分治块,答案加上树状数组上的值,在减去\(x\)所在的那颗子树的贡献即可。
具体的,对于每个点,开个\(vector\)记录一些四元组,表示分治重心,所在的儿子子树的儿子的编号,到分治重心的距离,以及重心的儿子的树状数组的编号。
然后大力出奇迹,多\(dfs\)几遍就做完了。
注意树状数组需要动态开点,可以对于每个树状数组算出一个最大可以访问到的\(dep\),然后动态分配内存,这个小\(trick\)具体可以看代码,树状数组的\(build\)部分。
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}
const int maxn = 2e5+10;
int n,m,val[maxn],tot,head[maxn];
struct edge{int to,nxt;}e[maxn<<1];
void add(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
void ins(int u,int v) {add(u,v),add(v,u);}
int space[maxn*100],pos,cnt;
struct Binary_Indexed_Tree {
int len,*t;
void build(int l) {len=l,t=space+pos+2,pos+=l+4;}
void modify(int x,int v) {for(int i=x;i<=len;i+=i&-i) t[i]+=v;}
int query(int x,int ans=0) {
if(x<=0) return 0;x=min(x,len);
for(int i=x;i;i-=i&-i) ans+=t[i];return ans;
}
}bit[maxn];
int rt,sz[maxn],f[maxn],vis[maxn],siz,mxdep[maxn],dep[maxn],h[maxn];
struct data {int x,y,dis,bel;};
vector<data > s[maxn];
map<int,int > r[maxn];
void get_rt(int x,int fa) {
sz[x]=1,f[x]=0;
for(int i=head[x];i;i=e[i].nxt)
if(!vis[e[i].to]&&e[i].to!=fa)
get_rt(e[i].to,x),sz[x]+=sz[e[i].to],f[x]=max(f[x],sz[e[i].to]);
f[x]=max(f[x],siz-sz[x]);
if(f[rt]>f[x]) rt=x;
}
void get_mxdep(int x,int fa) {
dep[x]=dep[fa]+1,mxdep[x]=dep[x];
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa&&!vis[e[i].to]) {
get_mxdep(e[i].to,x);
mxdep[x]=max(mxdep[x],mxdep[e[i].to]);
}
}
int de,de2;
void make(int x,int fa) {
bit[cnt].modify(dep[x],val[x]);
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa&&!vis[e[i].to]) make(e[i].to,x);
}
void mark(int x,int fa,int a,int y,int d,int b) {
s[x].push_back((data){a,y,d,b});
for(int i=head[x];i;i=e[i].nxt)
if(!vis[e[i].to]&&e[i].to!=fa) mark(e[i].to,x,a,y,d+1,b);
}
void build(int x) {
get_mxdep(x,0);
cnt++;h[x]=cnt;
bit[cnt].build(mxdep[x]);
de=x;make(x,0);
for(int i=head[x];i;i=e[i].nxt)
if(!vis[e[i].to]) {
dep[x]=0;get_mxdep(e[i].to,x);cnt++;
bit[cnt].build(mxdep[e[i].to]+1);
de=0;make(e[i].to,x);
mark(e[i].to,x,x,e[i].to,1,cnt);
}
vis[x]=1;
for(int i=head[x];i;i=e[i].nxt)
if(!vis[e[i].to]) {
get_rt(e[i].to,0),siz=sz[e[i].to],rt=0;
get_rt(e[i].to,0),build(rt);
}
}
void change(int x,int y) {
vector<data > :: iterator it;
for(it=s[x].begin();it!=s[x].end();it++) {
data da=*it;
bit[h[da.x]].modify(da.dis+1,y-val[x]);
bit[da.bel].modify(da.dis,y-val[x]);
}
bit[h[x]].modify(1,y-val[x]);
val[x]=y;
}
int query(int x,int y) {
int ans=0;
vector<data > :: iterator it;
for(it=s[x].begin();it!=s[x].end();it++) {
data da=*it;
ans+=bit[h[da.x]].query(y-da.dis+1);
ans-=bit[da.bel].query(y-da.dis);
}
ans+=bit[h[x]].query(y+1);
return ans;
}
int main() {
read(n),read(m);
for(int i=1;i<=n;i++) read(val[i]);
for(int i=1,x,y;i<n;i++) read(x),read(y),ins(x,y);
siz=n,f[0]=maxn,get_rt(1,0),build(rt);
int lstans=0;
for(int i=1;i<=m;i++) {
int op,x,y;read(op),read(x),read(y);
x^=lstans,y^=lstans;
if(op==1) change(x,y);
else write(lstans=query(x,y));
}
return 0;
}
标签:解密 odi ons ack vector math 需要 build 树状数组
原文地址:https://www.cnblogs.com/hbyer/p/10263883.html