动态点分治:bzoj 3730,bzoj 1095

总结一下动态点分治的模板。。。

对于一个树,把它点分的同时记录每个点的所有父亲(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<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define inf (1<<30)
#define maxn 100100
using namespace std;
struct set{
    priority_queue<int>pq,_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<n;i++)
        scanf("%d%d",&u,&v),addedge(u,v);
    for(int i=1;i<=n;++i)col[i]=1;
    solve(1);
    for(int i=1;i<=n;++i)if(fa[i][dep[i]]&&st[i].size())son[fa[i][dep[i]]].push(st[i].top());//,printf("[%d->%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<vector> 
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<sys/mman.h>
#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(mxsize<s[e[t].r])mxsize=s[e[t].r];
        }
    if(mxsize<sz-s[u])mxsize=sz-s[u];
    if(mn>mxsize)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<n;++i)u=rd(),v=rd(),addedge(u,v);
    solve(1);
    for(int i=1;i<=n;++i)fa[i][dep[i]+1]=i;
    for(int i=1;i<=n;++i)change(i);
//  change(6);
    for(int i=1,lst=0;i<=m;++i){
        int op,x,y;op=rd(),x=rd(),y=rd();
        x^=lst,y^=lst;
        if(op==0)printf("%d\n",lst=qsum(x,y));
        else key[x]=-key[x],change(x),key[x]=y,change(x);
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值