POJ 2763

来源:互联网 发布:总裁小说改编的网络剧 编辑:程序博客网 时间:2024/06/01 10:19

题意:给定一棵含n个结点的树,共有q次操作,分为两种

0 c :求从位置s到c的距离,然后s变成c

1 a b:把第a条边的权值变为b

n<10w,q<10w

题解:求树中两点距离显然是LCA,关于对原树中边权的修改,假设改了(a,b)使得其边增大了c,那么如果a是b的父亲,那么以b为子树的所有结点到根的距离都将增加c。求解LCA可以得到dfs序列,记录下每个结点初始访问时间以及最后访问时间,那么如果以该节点为子树的结点距根节点距离有变,只需对这个区间内每个值加上c即可,线段树可以做,但太麻烦了,实际上可以用树状数组直接在这区间头加上c,区间尾后面减去c,然后求值时受影响的就只有这个区间了。

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int N = 400005; // 1<<20;int prt[N],pnt[N], next[N], head[N],cost[N]; // 邻接表bool visited[N]; // 初始为0,从根遍历int e,id;int dep[N], E[N], R[N],ED[N],fa[N],dist[N]; // dep:dfs遍历节点深度, E:dfs序列, R:第一次被遍历的下标void DFS(int u, int d);int d[40], st[N][40];int ar[N]; // index: 1 ~ Nint lowb(int t){    return t&(-t) ;}void add(int i, int v){    for ( ; i < N; ar[i] += v, i += lowb(i));}int sum(int i){    int s = 0;    for ( ; i > 0; s += ar[i], i -= lowb(i));    return s;}int Query(int x, int y){    int k;    k = int( log(double(y-x+1))/log(2.0) );    return dep[ st[x][k] ] > dep[ st[y-d[k]+1][k] ] ? st[y-d[k]+1][k] : st[x][k];}int LCA(int x,int y){    if( x > y )        swap(x,y);    return E[Query(x, y)];}void DFS(int u, int d,int dis){    visited[u] = 1;    R[u] = id;    E[id] = u;    dist[u]=dis;    dep[id++] = d;    for( int i=head[u]; i != -1; i=next[i] )        if( visited[ pnt[i] ] == 0 )        {            fa[pnt[i]]=u;            DFS(pnt[i], d+1,cost[i]+dis);            E[id] = u;            dep[id++] = d;        }    ED[u]=id;}void InitRMQ(){    int i, j;    for( d[0]=1, i=1; i < 20; ++i ) d[i] = 2*d[i-1];    for( i=0; i < id; ++i ) st[i][0] = i;    int k = int( log(double(N))/log(2.0) ) + 1;    for( j=1; j < k; ++j )        for( i=0; i < id; ++i )            if( i+d[j-1]-1 < id )                st[i][j]=dep[st[i][j-1]]>dep[ st[i+d[j-1]][j-1]]?st[i+d[j-1]][j-1]:st[i][j-1];            else break;}void addedge(int a,int b,int c){    prt[e]=a;pnt[e]=b;next[e]=head[a];cost[e]=c;head[a]=e++;    prt[e]=b;pnt[e]=a;next[e]=head[b];cost[e]=c;head[b]=e++;}struct Edge{    int a,b,c;    Edge(){}    Edge(int _a,int _b,int _c)    {        a=_a,b=_b,c=_c;    }}EE[N];int main(){    int n,q,s,a,b,c,op,x,y,z;    while(scanf("%d%d%d",&n,&q,&s)!=EOF)    {        memset(head,-1,sizeof(head));        memset(ar,0,sizeof(ar));        memset(visited,0,sizeof(visited));        id=e=0;        for(int i=1;i<n;i++)        {            scanf("%d%d%d",&a,&b,&c);            EE[i]=Edge(a,b,c);            addedge(a,b,c);        }        DFS(s,0,0);        fa[s]=s;        InitRMQ();        for(int i=0;i<q;i++)        {            scanf("%d",&op);            if(op==0)            {                scanf("%d",&b);                x=R[s];y=R[b];z=R[c=LCA(x,y)];                printf("%d\n",sum(x+1)+sum(y+1)-2*sum(z+1)+dist[s]+dist[b]-2*dist[c]);                s=b;            }            else            {                scanf("%d%d",&a,&c);                x=EE[a].a;                y=EE[a].b;                int tp=c-EE[a].c;                EE[a].c=c;                if(fa[x]==y)                    swap(x,y);                add(R[y]+1,tp);                add(ED[y]+1,-tp);            }        }    }    return 0;}


原创粉丝点击