BZOJ 3730 震波
题目链接:震波
这道题有种紫荆花之恋的既视感→_→
于是我果断写了点分+treap,结果这道题卡常数,\(treap\)被生生卡掉了……看来我以前低估了\(treap\)的常数……
于是我一气之下把\(treap\)改成了线段树,然后发现空间似乎多了一个\(\log\)……接着仔细想了想,发现由于每棵子树有用的下标是连续的一段,那么我只需要控制一下每棵线段树维护的区间,那么每棵线段树所用空间就是\(O(size)\)的了,于是总空间就变成了\(O(n\log n)\)……
UPD:好像不需要这样,空间直接就是\(O(n\log n)\)的……因为只有一段区间内的下标是有用的,所以线段树只会开\(O(size+\log n)\)的空间……(捂脸
还是讲讲做法吧。首先,两个点之间的路径必然会经过他们在点分树上的$lca$(这不是废话么)。我们把点分的结构维护下来,对每个节点\(u\)开一棵线段树,维护它的子树中到\(u\)距离为\(x\)的所有点的点权和。然后查询时一路往上跳,在线段树中查询即可。
但是这样显然是会算重的。于是我没对每个节点再维护一棵线段树,维护每个点到$father_u$(\(u\)在点分树上的父亲)的距离,跳的时候加加减减就做完了。当然这里省略了很多细节……留给写这道题的人自己去发现。
还有没有异或上次的\(ans\)导致无限RE……不开心……
下面贴代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 100010
#define MAXN maxn*50
using namespace std;
typedef long long llg;
int n,m,a[maxn],fa[maxn],siz[maxn],dx[maxn];
int head[maxn],next[maxn<<1],to[maxn<<1],tt,dep[maxn];
int dis[maxn][30],d[maxn],ld,du[maxn],co[maxn][2];
int val[MAXN],zhi[MAXN],sumv[MAXN],ans;
int s[MAXN][2],rt[maxn][2],R,Z,_sum;
bool vis[maxn];
int getint(){
int w=0;bool q=0;
char c=getchar();
while((c>'9'||c<'0')&&c!='-') c=getchar();
if(c=='-') c=getchar(),q=1;
while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
return q?-w:w;
}
void link(int x,int y){
to[++tt]=y;next[tt]=head[x];head[x]=tt;
to[++tt]=x;next[tt]=head[y];head[y]=tt;
}
inline void add(int &x,int l,int r){
if(!x) x=++tt; int u=x;
sumv[u]+=Z; int mid;
while(l!=r){
mid=(l+r)>>1;
if(R<=mid) u=(s[u][0]?s[u][0]:s[u][0]=++tt),r=mid;
else u=(s[u][1]?s[u][1]:s[u][1]=++tt),l=mid+1;
sumv[u]+=Z;
}
}
inline void query(int u,int l,int r){
if(R<l) return;
while(l!=r){
if(!u || r<=R) break; int mid=(l+r)>>1;
if(R<=mid) u=s[u][0],r=mid;
else _sum+=sumv[s[u][0]],l=mid+1,u=s[u][1];
}
_sum+=sumv[u];
}
void dfs2(int u,int now){
vis[u]=1; siz[u]=1; dx[u]=0; d[++ld]=u; du[ld]=now;
for(int i=head[u],v;v=to[i],i;i=next[i])
if(!vis[v]) dfs2(v,now+1),siz[u]+=siz[v],dx[u]=max(dx[u],siz[v]);
vis[u]=0;
}
void dfs1(int x,int ff){
ld=0; dfs2(x,0); int k=0;
for(int i=1,u;u=d[i],i<=ld;i++){
dx[u]=max(dx[u],siz[x]-siz[u]);
if(dx[u]<dx[k]) k=u;
}
ld=0; dfs2(k,0); vis[k]=1; fa[k]=ff;
dep[k]=dep[ff]+1;
for(int i=1,u;u=d[i],i<=ld;i++){
co[k][0]=max(co[k][0],du[i]);
co[k][1]=max(co[k][1],dis[u][dep[ff]]);
}
for(int i=1,u;u=d[i],i<=ld;i++){
Z=a[u]; R=dis[u][dep[k]]=du[i],add(rt[k][0],0,co[k][0]);
if(ff) R=dis[u][dep[ff]],add(rt[k][1],1,co[k][1]);
}
for(int i=head[k],v;v=to[i],i;i=next[i])
if(!vis[v]) dfs1(v,k);
}
int main(){
File("a");
n=getint(); m=getint(); dx[0]=n+1;
for(int i=1;i<=n;i++) a[i]=getint();
for(int i=2;i<=n;i++) link(getint(),getint());
tt=0; dfs1(1,0);
while(m--){
int ty=getint(),x=getint()^ans,y=getint()^ans;
if(!ty) ans=0;
for(int u=x,d=dep[x];u;u=fa[u],d--){
if(!ty) R=y-dis[x][d],_sum=0,query(rt[u][0],0,co[u][0]),ans+=_sum;
else R=dis[x][dep[u]],Z=y-a[x],add(rt[u][0],0,co[u][0]);
if(fa[u])
if(!ty) R=y-dis[x][d-1],_sum=0,query(rt[u][1],1,co[u][1]),ans-=_sum;
else R=dis[x][dep[fa[u]]],Z=y-a[x],add(rt[u][1],1,co[u][1]);
}
if(ty) a[x]=y;
else printf("%d\n",ans);
}
return 0;
}
老年选手BZOJ 终于233题辣!(现在才刷了这么点题的我真是一条咸鱼)

浙公网安备 33010602011771号