对于一个树,把它点分的同时记录每个点的所有父亲(logn个)并记录点距其父亲的距离。
具体实现就是dfs的时候fa[x][++dep[x]]=u,dis[x][dep[x]]=d;
BZOJ1095:
您需要写一个程序支持反转点的颜色,求距离最远的黑色点对的距离。
解析:在每个点u存一个堆st记录该子树(分治中的)中点到fa[u]的距离再存一个堆son记录他所有儿子的st.top()
最后再用一个总的堆维护直径。
修改的时候就从点u开始向上爬,将fa[u]的son $#%^% 一下,再修改u的st。
#include
#include
#include
#include
#include
#define inf (1<<30)
#define maxn 100100
using namespace std;
struct set{
priority_queuepq,_del;
void push(int x){ pq.push(x); }
void del(int x){ _del.push(x); }
void pop(){ pq.pop(); }
int top(){
while(_del.size()&&pq.top()==_del.top())pq.pop(),_del.pop();
return pq.top();
}
int size(){
return pq.size()-_del.size();
}
int maxlen(){
int a=top();
pop();
int b=top();
return push(a),a+b;
}
}st[maxn],all,son[maxn];
struct edge{
int r,nxt;
}e[maxn<<1];
int b[20],light=0,col[maxn],head[maxn],esz,fa[maxn][18],dep[maxn],mn,rt,vis[maxn],s[maxn],dis[maxn][18],n,m,sz;
void addedge(int u,int v){
e[++esz].r=v;e[esz].nxt=head[u];head[u]=esz;
e[++esz].r=u;e[esz].nxt=head[v];head[v]=esz;
}
void init(int u,int f){
sz++;
for(int t=head[u];t;t=e[t].nxt)
if(e[t].r!=f&&!vis[e[t].r])init(e[t].r,u);
}
void getroot(int u,int f){
int mxsize=0;s[u]=1;
for(int t=head[u];t;t=e[t].nxt)
if(e[t].r!=f&&!vis[e[t].r]){
getroot(e[t].r,u),s[u]+=s[e[t].r];
mxsize=max(mxsize,s[e[t].r]);
}
mxsize=max(mxsize,sz-s[u]);
if(mn>mxsize)mn=mxsize,rt=u;
}
void build(int u,int f,int x,int d){
for(int t=head[u];t;t=e[t].nxt)
if(e[t].r!=f&&!vis[e[t].r]){
fa[e[t].r][++dep[e[t].r]]=x;
dis[e[t].r][dep[e[t].r]]=d+1;
build(e[t].r,u,x,d+1);
}
}
void calc(int u,int f,int x){
if(u==x)st[x].push(dis[u][dep[u]]);
else st[x].push(dis[u][dep[u]-1]);//printf("[%d->%d:%d,%d]\n",fa[x][dep[x]],u,dis[u][dep[u]-1],fa[u][dep[u]]);
for(int t=head[u];t;t=e[t].nxt)
if(e[t].r!=f&&!vis[e[t].r])calc(e[t].r,u,x);
}
void solve(int u){
mn=inf,sz=0,init(u,0),getroot(u,0);
vis[u=rt]=true,build(u,0,u,0);calc(u,0,u);
son[u].push(0);//printf("[%d]\n",u);
for(int t=head[u];t;t=e[t].nxt)
if(!vis[e[t].r])solve(e[t].r);
}
void change(int i){
if(col[i]){
light--;
if(son[i].size()>1)all.del(son[i].maxlen());
son[i].del(0);
if(son[i].size()>1)all.push(son[i].maxlen());
for(int j=dep[i]+1;j>=2;j--){
int nw=fa[i][j],pre=fa[i][j-1];
// if(fa[nw][dep[nw]]!=pre)exit(-1);
if(son[pre].size()>1)all.del(son[pre].maxlen());//printf("[ok:%d]",son[pre].maxlen());
// printf("<%d>",st[nw].top()+1);
if(st[nw].size())son[pre].del(st[nw].top());
// printf("<%d>",st[nw].top());
st[nw].del(dis[i][j-1]);
// printf("<%d,%d>",dis[i][j-1],st[nw].top());
if(st[nw].size())son[pre].push(st[nw].top());
if(son[pre].size()>1)all.push(son[pre].maxlen());//printf("[ok:%d]",son[pre].maxlen());
}
} else {
light++;
if(son[i].size()>1)all.del(son[i].maxlen());
son[i].push(0);
if(son[i].size()>1)all.push(son[i].maxlen());
for(int j=dep[i]+1;j>=2;j--){
int nw=fa[i][j],pre=fa[i][j-1];
if(son[pre].size()>1)all.del(son[pre].maxlen());
if(st[nw].size())son[pre].del(st[nw].top());
st[nw].push(dis[i][j-1]);
if(st[nw].size())son[pre].push(st[nw].top());
if(son[pre].size()>1)all.push(son[pre].maxlen());
}
}
col[i]=!col[i];
}
int main(){
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
scanf("%d",&n);light=n;
for(int i=1,u,v;i%d:%d]",i,fa[i][dep[i]],st[i].top());
for(int i=1;i<=n;++i)if(son[i].size()>1)all.push(son[i].maxlen());//printf("[%d:%d]",i,son[i].maxlen());
for(int i=1;i<=n;++i)fa[i][dep[i]+1]=i;
scanf("%d",&m);
for(int i=1,x;i<=m;++i){
// printf("[%d]\n",light);
char op[2];scanf("%s",op);
if(op[0]=='C')scanf("%d",&x),change(x);
else printf("%d\n",light>1?all.top():light-1);
}
}
BZOJ 3730
在一片土地上有N个城市,通过N-1条无向边互相连接,形成一棵树的结构,相邻两个城市的距离为1,其中第i个城市的价值为value[i]。
不幸的是,这片土地常常发生地震,并且随着时代的发展,城市的价值也往往会发生变动。
接下来你需要在线处理M次操作:
0 x k 表示发生了一次地震,震中城市为x,影响范围为k,所有与x距离不超过k的城市都将受到影响,该次地震造成的经济损失为所有受影响城市的价值和。
1 x y 表示第x个城市的价值变成了y。
对每个点设一个树状数组bit存点到根的距离,fbit存点到跟的fa的距离,大小为树高
于是就可以容斥了:ans+=bit(k-dis)-fbit(k-dis);
修改什么的都暴力爬树就可
#include
#include
#include
#include
#include
#include
#define inf (1<<30)
#define maxn 100100
using namespace std;
struct edge{
int r,nxt;
}e[maxn<<1];
int rt,mn,head[maxn],key[maxn],n,m,fa[maxn][18],dep[maxn],esz,dis[maxn][18],vis[maxn],sz,s[maxn];
int *bit[maxn],*fbit[maxn],size[maxn];
void addedge(int u,int v){
e[++esz].r=v;e[esz].nxt=head[u];head[u]=esz;
e[++esz].r=u;e[esz].nxt=head[v];head[v]=esz;
}
void init(int u,int f){
sz++;
for(int t=head[u];t;t=e[t].nxt)
if(e[t].r!=f&&!vis[e[t].r])init(e[t].r,u);
}
void getroot(int u,int f){
int mxsize=0; s[u]=1;
for(int t=head[u];t;t=e[t].nxt)
if(e[t].r!=f&&!vis[e[t].r]){
getroot(e[t].r,u),s[u]+=s[e[t].r];
if(mxsizemxsize)mn=mxsize,rt=u;
}
void build(int u,int f,int x,int d){
size[x]=max(size[x],d);
for(int t=head[u];t;t=e[t].nxt)
if(e[t].r!=f&&!vis[e[t].r]){
int v=e[t].r;
fa[v][++dep[v]]=x;
dis[v][dep[v]]=d+1;
build(v,u,x,d+1);
}
}
void solve(int u){
mn=inf,sz=0,init(u,0),getroot(u,0);
u=rt;vis[u]=true;
build(u,0,u,0);
size[u]=min(sz,size[u]*2+2);
bit[u]=(int*)calloc(size[u]+1,4);
fbit[u]=(int*)calloc(size[u]+1,4);
for(int t=head[u];t;t=e[t].nxt)if(!vis[e[t].r])solve(e[t].r);
}
void modify(int* bit,int lim,int x,int a){
for(;x<=lim&&x;x+=x&-x)bit[x]+=a;
}
void change(int i){
modify(fbit[i],size[i],dis[i][dep[i]],key[i]);
for(int j=1;j<=dep[i];++j)
modify(bit[fa[i][j]],size[fa[i][j]],dis[i][j],key[i]),
modify(fbit[fa[i][j]],size[fa[i][j]],dis[i][j-1],key[i]);
}
int query(int *bit,int x){
// printf("[%d]\n",x);
int ans=0;
for(;x;x-=x&-x)ans+=bit[x];
return ans;
}
int qsum(int x,int k){
int ans=query(bit[x],min(k,size[x]))+key[x];
for(int i=1;i<=dep[x];++i)if(dis[x][i]<=k)
ans+=query(bit[fa[x][i]],min(size[fa[x][i]],k-dis[x][i]))+key[fa[x][i]]-query(fbit[fa[x][i+1]],min(size[fa[x][i+1]],k-dis[x][i]));
return ans;
}
struct _i{char *p;_i(){p=(char*)mmap(NULL,10000000,PROT_READ,MAP_PRIVATE,fileno(stdin),0);
}inline int operator()(){int r=0;while(*p<'0')p++;while(*p>='0')r=r*10+*(p++)-'0';return r;}}rd;
int main(){
n=rd(),m=rd();
for(int i=1;i<=n;++i)key[i]=rd();
for(int i=1,u,v;i