动态点分治:bzoj 3730,bzoj 1095

来源:互联网 发布:域名收录查询 编辑:程序博客网 时间:2024/05/14 13:10
总结一下动态点分治的模板。。。

对于一个树,把它点分的同时记录每个点的所有父亲(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 100100using 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 100100using 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