hdu5296

来源:互联网 发布:越狱苹果抹除所有数据 编辑:程序博客网 时间:2024/06/06 19:08

题意:给定一颗边权树,动态地在点集中增加和删除点。求当前所在点集中使得所有点都连通的最小边权和。
解法:
首先介绍一个结论:
树上点u到以x和y为端点的链的最段距离可以在O(n)预处理和O(logn)时间复杂度内求出。
证明:设z=lca(x,y),dis[u]为树中点u到跟节点的路径权值和。则dis< u,(x,y) >=dis[u]-dis[lca(u,x)]-dis[lca(u,y)]+dis[z]。lca均可在O(logn)内求出,得证!
推论如下:
判断树上某点u是否在链(x,y)上可以在O(logn)复杂度内求出
求dis< u,(x,y) >,结果为0则在链(x,y)上,反之不在。
求链(x1,y1)和链(x2,y2)的最段距离可以在O(logn)复杂度内求出
设z1=lca(x1,y1),z2=lca(x2,y2),不妨设z1高度更高。则z2到(x1,y1)距离即为链(x2,y2)到(x1,y2)距离
另一个结论是:
树中一系列点的lca和dfs序最小和最大的点的lca相同
该结论等价于定点u和动点v的lca随v的dfs序增大而不减。这个结论很显然通过v的移动可以看出确实如此。
回到本题。先求树中每点的dfs序。如果添加的点u在已知点集中存在dsf序比它小的最大点x和dfs序比它大的最小点y,那么增加的权值和即为u到达链(x,y)的距离,这个结论可以通过实验x和y的不同相对位置得到;如果所有点的dfs序都比y的dfs序大或小,那么只要求出dfs序的最大和最小值对应顶点x和y,求u到链(x,y)距离即可,这可以由上述结论证明正确性。

#include<stdio.h>#include<string.h>#include<iostream>#include<vector>#include<math.h>#include<set>#include<algorithm>#define ll intusing namespace std;const int maxn = 100000+10;int t,n,q;struct Edge{    int to,w,next;}edge[maxn<<2];int head[maxn],tot;void add(int u,int v,int w) { edge[tot].to=v,edge[tot].w=w,edge[tot].next=head[u],head[u]=tot++; }int father[maxn], fa[maxn][20+3], deep[maxn];bool vis[maxn];int dis[maxn],dfst[maxn],dfs_clock,id[maxn];int tmpans;set<int> se;set<int>::iterator iter;void dfs(int u,int f) {    deep[u] = deep[f]+1; father[u]=f; dfst[u]=++dfs_clock; id[dfs_clock]=u;    for(int i=head[u];i!=-1;i=edge[i].next){        int v=edge[i].to,w=edge[i].w;;        if(v==f) continue;        dis[v]=dis[u]+w;        dfs(v,u);    }}void init() {    deep[0]=0,dis[1]=0,dfs_clock=0;    dfs(1,0);    for(ll i=1;i<=n;i++) fa[i][0]=father[i];    for(ll j=1;j<=18;j++) for(ll i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1];}int lca(int x,int y) {    if (deep[x] < deep[y]) swap(x, y);    int delta = deep[x] - deep[y];    for(int j=0;j<=18;j++) if ((1<<j) & delta) x = fa[x][j];    if (x == y) return x;    for(int j=18;j>=0;j--) if (fa[x][j] != fa[y][j]) x = fa[x][j], y = fa[y][j];    return fa[x][0];}int fun(int u){    if(!se.size()) return 0;    iter=se.lower_bound(dfst[u]);    int x,y; bool flag=false;    if(iter!=se.end()){        y=*iter; y=id[y];        if(iter!=se.begin()){            iter--; x=*iter; x=id[x];            flag=true;        }    }    if(!flag){        iter=se.begin(); x=*iter; x=id[x];        iter=se.end(); iter--; y=*iter; y=id[y];    }    int tmp=dis[u]-dis[lca(u,x)]-dis[lca(u,y)]+dis[lca(x,y)];    return tmp;}int main(){    //freopen("a.txt","r",stdin);    scanf("%d",&t);    for(int cas=1;cas<=t;cas++){        scanf("%d%d",&n,&q);        memset(head,-1,sizeof(head)); tot=0;        memset(vis,0,sizeof(vis));        se.clear();        for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); }        init(); tmpans=0;        printf("Case #%d:\n",cas);        for(int i=1;i<=q;i++){            int x,u; scanf("%d%d",&x,&u);            if(x==1&&!vis[u]) { vis[u]=1; tmpans+=fun(u); se.insert(dfst[u]); }            else if(x==2&&vis[u]) { vis[u]=0; se.erase(dfst[u]); tmpans-=fun(u); }            printf("%d\n",tmpans);        }    }    return 0;}
0 0
原创粉丝点击