题意:在一棵只有点权的树上在线求据一个点x距离为k的点权和
一言不合又是200+,而且还卡常~~~卡常~~~,幸好机智地加了读入输出优化险险地卡了过去 /笑
每个节点建立两个线段树,以到点的距离为下标,记录权值和。第一棵记录其作为点分数父节点遍历其统治的子树的以距离为下标的点权和。由于点分树树高仅logn,暴力翻树高,在其经过的点分树祖先节点上查询距离为的k-now的点权和(now即为x到此祖先节点的距离,利用倍增lca)。然而需要注意一点,即为父节点统计和子节点会重合,这部分即在分治子树。这里需要容斥掉重复部分,于是需要每个节点再建立一棵线段树,记录父节点在子树中与子节点的重合部分,这部分需要记录到子节点中。查询时暴力翻树高,线段树查询并容斥即可。
觉得还是自己代码写得舒服QvQ,就是有点长233,还有点慢(status上倒数前十hhh)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define ff st
using namespace std;
const int maxn=500005;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x;
}
inline void write(int x)
{
if(x>9)write(x/10);
putchar(x%10+'0');
}
struct tree
{
long long sum;int lson,rson;
}t[maxn<<4];
struct edge
{
int to,next;
}e[maxn<<1];
int n,q,s[maxn];//题设
int cnt,head[maxn];//链式前向星
int cnt_clock,root[maxn][2];//线段树
int sz[maxn],mxsz[maxn];//dfs求重心
bool vst[maxn];//点分树
int pere[maxn];//点分树
int st[maxn][25],dep[maxn];//倍增lca
inline void insert(int a,int b)
{
e[++cnt].to=b;e[cnt].next=head[a];head[a]=cnt;
}
void dfs_init(int x,int fa,int depth)
{
st[x][0]=fa;
dep[x]=depth;
for(int i=head[x];i;i=e[i].next)
{
if(e[i].to==fa)continue;
dfs_init(e[i].to,x,depth+1);
}
}
void dfs_geto(int x,int fa,int tot,int &o)
{
sz[x]=1;
mxsz[x]=0;
for(int i=head[x];i;i=e[i].next)
{
if(e[i].to==fa||vst[e[i].to])continue;
dfs_geto(e[i].to,x,tot,o);
sz[x]+=sz[e[i].to];
mxsz[x]=max(mxsz[x],sz[e[i].to]);
}
mxsz[x]=max(mxsz[x],tot-sz[x]);
if(mxsz[x]<mxsz[o])o=x;
}
void dfs_getsz(int x,int fa)
{
sz[x]=1;
for(int i=head[x];i;i=e[i].next)
{
if(e[i].to==fa||vst[e[i].to])continue;
dfs_getsz(e[i].to,x);
sz[x]+=sz[e[i].to];
}
}
void st_chart()
{
for(int j=1;j<=23;j++)
for(int i=1;i<=n;i++)
st[i][j]=st[st[i][j-1]][j-1];
}
int getlca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
int tmp=dep[x]-dep[y];
int pos=0;
while(tmp)
{
if(tmp&1)x=st[x][pos];
pos++;
tmp>>=1;
}
if(x==y)return x;
for(int i=22;i>=0;i--)
if(st[x][i]!=st[y][i])
{
x=st[x][i];
y=st[y][i];
}
return st[x][0];
}
inline int getdist(int x,int y)
{
return dep[x]+dep[y]-2*dep[getlca(x,y)];
}
int query(int ro,int lt,int rt,int l,int r)
{
if(lt==l&&rt==r)
return t[ro].sum;
int mid=(lt+rt)>>1;
if(r<=mid)return query(t[ro].lson,lt,mid,l,r);
else if(l>=mid+1)return query(t[ro].rson,mid+1,rt,l,r);
return
query(t[ro].lson,lt,mid,l,mid)+
query(t[ro].rson,mid+1,rt,mid+1,r);
}
void increase(int &ro,int l,int r,int pos,int val)
{
if(!ro)ro=++cnt_clock;
t[ro].sum+=val;
if(l==r)return;
int mid=(l+r)>>1;
if(pos<=mid)increase(t[ro].lson,l,mid,pos,val);
else increase(t[ro].rson,mid+1,r,pos,val);
}
void traversal(int rt,int x,int fa,int depth,bool d)
{
increase(root[rt][d],0,n,depth,s[x]);
for(int i=head[x];i;i=e[i].next)
if(e[i].to!=fa&&!vst[e[i].to])
{
int y=e[i].to;
traversal(rt,y,x,depth+1,d);
}
}
void visit_o(int x)
{
vst[x]=true;
traversal(x,x,0,0,0);
for(int i=head[x];i;i=e[i].next)
{
if(vst[e[i].to])continue;
int rt=0,y=e[i].to;
dfs_geto(y,x,sz[y],rt);
pere[rt]=x;
traversal(rt,y,x,1,1);
visit_o(rt);
}
}
void tree_change(int x,int val)
{
int pos=x;
int add=val-s[x];
increase(root[x][0],0,n,0,add);
while(pere[x])
{
int now=getdist(pere[x],pos);
increase(root[pere[x]][0],0,n,now,add);
increase(root[x][1],0,n,now,add);
x=pere[x];
}
s[pos]=val;
}
int tree_query(int x,int k)
{
int res=query(root[x][0],0,n,0,k);
int pos=x;
while(pere[x])
{
int now=getdist(pere[x],pos);
if(k<now){x=pere[x];continue;}
res+=query(root[pere[x]][0],0,n,0,k-now);
res-=query(root[x][1],0,n,0,k-now);
x=pere[x];
}
return res;
}
int main()
{
n=read(),q=read();
for(int i=1;i<=n;i++)
s[i]=read();
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
insert(a,b);
insert(b,a);
}
dfs_init(1,0,1);
st_chart();
mxsz[0]=0x3f3f3f3f;
int tr=0;
dfs_geto(1,0,n,tr);
visit_o(tr);
int pre=0;
for(int i=1;i<=q;i++)
{
int o,x,y;
o=read(),x=read(),y=read();
x=x^pre;y=y^pre;
if(o==1)
tree_change(x,y);
else
write(pre=tree_query(x,y)),putchar('\n');
}
return 0;
}