前言
这一道题做了我两天,考试时都在做,搞得我爆零了,原因下面会提到.
题面
原题描述已经很简洁,故您只需戳.
原题数据从时间上看很水,从空间上看有点卡。
sol
如果说告诉你这是一道点分治,思路实在不难。根据询问,每次只需要一层层的找那些能囊括自己的点。现在包含自己的等级最小的子树,然后更高级的子树。每一次通过子树的根寻找与自己不在同一子树的点。修改也很简单。
中心思路
把一次一个点的修改转变成以log个点的修改,把一次n个点的查询转变成log个点的查询
所以说每一个点都要开一个数据结构记录与自己不超过d的点要加上多少。一个点如果距自己为d那么他可以加上d,d+1,d+2…的值,这是一个区间求和。又注意到每一次修改一个点,所以是单点修改区间查询。因为是noip普及组以下的选手,果断选择树状数组.
网络上大佬都用线段树,还有动态开点和标记永久化,蒟蒻由于是noip普及组- 的选手,所以使用更加无脑,更加码量小,常数更小的树状数组。
每个点两个树状数组,一个tofa,一个dis。维护什么都知道,跟线段树的差不多。主要是空间问题。
注意到每一个点都开O(n)的开不下,那我们就像线段树那样一起开,因为一起开的大小大概小于两倍nlogn(用Re10次的情况试出来的)。
然后记录好每一个点的子树最深的是多少,这个要跑log遍dfs,和建分治树一起跑。最后按照长链剖分的指针思想在已经事先开好的空间内分配空间。
代码
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int _ = 1e5+1e2;
const int INF = 2e9;
namespace zjy_io{
inline char gc(){
static char buf[1<<6],*p1=buf,*p2=buf;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<6,stdin),p1==p2)?EOF:*p1++;
}
template <class T>
inline void read(T&data){
data=0;
register char ch=0;
register int caa=1;
while((ch<'0'||ch>'9')&&ch!='-')ch=gc();
ch=='-'?caa=-1,ch=gc():caa=1;
while(ch<='9'&&ch>='0'){
data=(data<<3)+(data<<1)+(ch&15);
ch=gc();
}
data*=caa;
}
inline char Getchar(){
register char ch=0;
while(ch<'A'||ch>'Z')ch=gc();
return ch;
}
}
using namespace zjy_io;
int mem[3000000],*pin=mem;
int n,m;
struct Tree_array{
int size,*tree;
int lowbit(register int k){return k&(-k);}
void init(register int kr){tree=pin,size=kr,pin+=size+3;}
void modify(register int loc,register int zh){
loc=min(loc,size),++loc;
for(register int i=loc;i<=size+1;i+=lowbit(i))tree[i]+=zh;
}
int query(register int l){
l>size?l=size:l=l;
register int ret1=0,ret2=0;
for(register int i=l;i;i-=lowbit(i))ret1+=tree[i];
for(register int i=size+1;i;i-=lowbit(i))ret2+=tree[i];
return ret2-ret1;
}
};
namespace d_tree{
int root,head[_],cnt,par[_];
void add(register int a,register int b){par[b]=a;}
Tree_array node1[_],node2[_];
}
struct orginal_tree{
struct edge{
int nt,to;
}e[_<<1];
int head[_],cnt,root,size[_],all,MX;
int dfn[_],fdfn[_],vis[_],dis[_],app[_],st[_<<1][18],tot,lg[_<<1];
int get_lca(register int u,register int v){
u=app[u],v=app[v];
if(u>v)swap(u,v);
register int LEN= lg[v-u+1];
return fdfn[min(st[u][LEN],st[v+1-(1<<LEN)][LEN])];
}
int getdist(register int u,register int v){return dis[u]+dis[v]-2*dis[get_lca(u,v)];}
void add(register int a,register int b){e[++cnt].to=b,e[cnt].nt=head[a],head[a]=cnt;}
void dfs(register int now,register int fa){
dfn[now]=++cnt,fdfn[cnt]=now,st[++tot][0]=cnt,app[now]=tot;
for(register int i=head[now];i;i=e[i].nt){
if(e[i].to==fa)continue;
dis[e[i].to]=dis[now]+1;
dfs(e[i].to,now);
st[++tot][0]=dfn[now];
}
}
int dfsI(register int now,register int fa){
int len_=0;
for(register int i=head[now];i;i=e[i].nt){
if(e[i].to==fa||vis[e[i].to])continue;
len_=max(len_,dfsI(e[i].to,now));
}
return len_+1;
}
void getroot(register int now,register int fa){
size[now]=1;
register int mx=0;
for(register int i=head[now];i;i=e[i].nt){
if(vis[e[i].to]||e[i].to==fa)continue;
getroot(e[i].to,now);
size[now]+=size[e[i].to];
mx=max(size[e[i].to],mx);
}
mx=max(mx,all-size[now]);
if(MX>mx)MX=mx,root=now;
}
void p_divide(register int now){
vis[now]=1;
for(register int i=head[now];i;i=e[i].nt){
if(vis[e[i].to])continue;
MX=INF;all=size[e[i].to];
getroot(e[i].to,now);
d_tree::add(now,root);
d_tree::node1[root].init(dfsI(root,0)-1);
p_divide(root);
}
}
void init(){
for(register int i=1,a,b;i<n;++i)read(a),read(b),add(a,b),add(b,a);
cnt=0;dfs(1,0);
register int us=2*n-1;
for(register int j=1;j<=17;++j)
for(register int i=1;i<=us&&i+(1<<(j-1))<=us;++i)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
for(register int i=2;i<=us;++i)lg[i]=lg[i>>1]+1;
MX=INF,all=n;
getroot(1,0);d_tree::node1[root].init(dfsI(root,0)-1);
d_tree::root=root;
p_divide(root);
}
}tr;
namespace d_tree{
void init(){ for(register int i=1;i<=n;++i) node2[i].init( node1[par[i]].size ); }
void modify(register int x,register int d,register int w){
node1[x].modify(d,w);
for(register int i=x;par[i];i=par[i]){
register int dist=tr.getdist(x,par[i]);
if(dist>d)continue;
node1[par[i]].modify(d-dist,w);
node2[i].modify(d-dist,w);
}
}
int query(register int x){
register int ret=0;
ret=node1[x].query(0);
for(register int i=x;par[i];i=par[i]){
register int dist=tr.getdist(x,par[i]);
ret=ret+node1[par[i]].query(dist);
ret=ret-node2[i].query(dist);
}
return ret;
}
}
int main(){
read(n),read(m);
tr.init();
d_tree::init();
register char frf;
register int a,b,c;
while(m--){
frf=Getchar();
if(frf=='M'){
read(a),read(b),read(c);
d_tree::modify(a,b,c);
}
else {
read(a);
printf("%d\n",d_tree::query(a));
}
}
}
总结
注意RE