hdu5044(树链剖分+标记法实现区间更新)

来源:互联网 发布:诚创cces电气设计软件 编辑:程序博客网 时间:2024/06/05 03:16
题意:一颗n个结点的树,两种操作: 1、将u到v之间的结点权值加k;2、将u到v之间的边权加k。输出经过修改后所有的边权和点权。

解题思路:做过树链剖分的应该都知道这题肯定是树链剖分题,其实就是一个模板题。但是注意点很多:1、结点有100000个,dfs的时候会爆栈,所以要扩栈; 2、这里的更新操作如果用线段树的update写,时间复杂度O(nlogn),会超时。 这里的成段更新很简单,而且是单点查询,只要用标记法就可以了,不需要用线段树。标记法时间复杂度O(n); 3、网上都说要输入优化才能过,所以我用读入优化写2078MS过的。不用输入优化也能过,时间3218MS。

代码如下:

#pragma comment(linker, "/STACK:1024000000,1024000000")#include<iostream>#include<algorithm>#include<stdio.h>#include<math.h>#include<cstring>#include<string>#include<vector>#define LL __int64#define N 100005#define inf 0x3f3f3f3f#define pi acos(-1.0)#define eps 10e-6using namespace std;int a[N][2],head[N];int tot;struct node{    int next,v,w;}edge[N*2];void addedge(int u,int v){    edge[tot].next = head[u];    edge[tot].v = v;    head[u] = tot++;}//----------树链剖分----------------------int siz[N],son[N],dep[N],fa[N];void dfs1(int u,int pa,int depth){    siz[u] = 1; son[u] = 0; fa[u] = pa; dep[u] = depth;    for(int i = head[u]; i != -1; i = edge[i].next)    {        int v = edge[i].v;        if(v == pa) continue;        dfs1(v,u,depth+1);        siz[u] += siz[v];        if(siz[v] > siz[ son[u] ])            son[u] = v;    }}int top[N],w[N],dfs_clock;void dfs2(int u,int pa){    w[u] = ++dfs_clock;    top[u] = pa;    if(son[u])        dfs2(son[u],pa);    for(int i = head[u]; i != -1; i = edge[i].next)    {        int v = edge[i].v;        if(v != son[u] && v != fa[u])            dfs2(v,v);    }}//------------标记法的区间更新------------------LL ans1[N],ans2[N];void change1(int x,int y,int k){    int f1 = top[x],f2 = top[y];    while(f1 != f2)    {        if(dep[f1] < dep[f2])        {            swap(x,y);            swap(f1,f2);        }        ans1[ w[f1] ] += k;        ans1[ w[x]+1 ] -= k;        x = fa[f1];        f1 = top[x];    }    if(w[x] > w[y]) swap(x,y);    ans1[ w[x] ] += k;    ans1[ w[y]+1 ] -= k;}void change2(int x,int y,int k){    int f1 = top[x],f2 = top[y];    while(f1 != f2)    {        if(dep[f1] < dep[f2])        {            swap(x,y);            swap(f1,f2);        }        ans2[ w[f1] ] += k;        ans2[ w[x]+1 ] -= k;        x = fa[f1];        f1 = top[x];    }    if(w[x] > w[y]) swap(x,y);    ans2[ w[x]+1 ] += k;    ans2[ w[y]+1 ] -= k;}inline bool scan_d(int &ret) {   char c; int sgn;   if(c=getchar(),c==EOF) return 0; //EOF   while(c!='-'&&(c<'0'||c>'9')) c=getchar();   sgn=(c=='-')?-1:1;   ret=(c=='-')?0:(c-'0');   while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');   ret*=sgn;   return 1;}int main(){    int t,cas = 1; //   scanf("%d",&t);    scan_d(t);    while(t--)    {        int n,m;      //  scanf("%d%d",&n,&m);        scan_d(n);        scan_d(m);        tot = 0;        memset(head,-1,sizeof(head));        for(int i = 1; i < n; i++){           // scanf("%d%d",&a[i][0],&a[i][1]);            scan_d(a[i][0]);            scan_d(a[i][1]);            addedge(a[i][0],a[i][1]);            addedge(a[i][1],a[i][0]);        }        memset(siz,0,sizeof(siz));        dfs1(1,0,1);        dfs_clock = 0;        dfs2(1,1);        memset(ans1,0,sizeof(ans1));        memset(ans2,0,sizeof(ans2));        while(m--)        {            char s[10];            int u,v,k;            //scanf("%s%d%d%d",s,&u,&v,&k);            scanf("%s",s);            scan_d(u);            scan_d(v);            scan_d(k);            if(s[3] == '1')                change1(u,v,k);            else change2(u,v,k);        }        for(int i = 2; i <= n; i++)        {            ans1[i] += ans1[i-1];            ans2[i] += ans2[i-1];        }        printf("Case #%d:\n",cas++);        int flag = 0;        for(int i = 1; i <= n; i++)        {            if(flag == 0)                printf("%I64d",ans1[ w[i] ]),flag = 1;            else printf(" %I64d",ans1[ w[i] ]);        }        printf("\n");        flag = 0;        for(int i = 1; i < n; i++)        {            if(dep[ a[i][0] ] < dep[ a[i][1] ])                swap(a[i][0],a[i][1]);            if(flag == 0)                printf("%I64d",ans2[ w[a[i][0]] ]),flag = 1;            else printf(" %I64d",ans2[ w[a[i][0]] ]);        }        printf("\n");    }    return 0;}


0 0
原创粉丝点击