hdu 5044 Tree (树链剖分+标记数组)

Posted kls123

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 5044 Tree (树链剖分+标记数组)相关的知识,希望对你有一定的参考价值。

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5044

这道题是真的有毒,之前用树链剖分+线段树写,tle了一万发,疯狂优化,最后放弃了,看了下其他人的题解

出题人卡了手线段树,不能用线段树写。。。。然后换成标记数组写(感觉比线段树要写起来要简单点。。),

然后还优化了输入。。结果还是TLE!!!!!

调试了一天多实在受不了了,交了发其他题解的代码上去。。。发现全部TLE。。。

就当自己这道题对了把。。。

 

实现代码:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid int m = (l + r) >> 1
const int M = 2e5+10;
struct node{
    int to,next;
}e[M];
int son[M],fa[M],head[M],siz[M],top[M],dep[M],tid[M],rk[M],a[M];
ll sum1[M],sum[M];
int cnt1,cnt,n;
void add(int u,int v){
    e[++cnt1].to = v;e[cnt1].next = head[u];head[u] = cnt1;
    e[++cnt1].to = u;e[cnt1].next = head[v];head[v] = cnt1;
}

void dfs1(int u,int faz,int deep){
     dep[u] = deep;
     fa[u] = faz;
     siz[u] = 1;
     for(int i = head[u];i;i=e[i].next){
        int v = e[i].to;
        if(v != fa[u]){
            dfs1(v,u,deep+1);
            siz[u] += siz[v];
            if(son[u] == -1||siz[v] > siz[son[u]])
                son[u] = v;
        }
     }
}

void dfs2(int u,int t){
    top[u] = t;
    tid[u] = cnt;
    rk[cnt] = u;
    //rk1[cnt] = wt[u];
    cnt++;
    if(son[u] == -1) return;
    dfs2(son[u],t);
    for(int i = head[u];i;i = e[i].next){
        int v = e[i].to;
        if(v != son[u]&&v != fa[u])
            dfs2(v,v);
    }
}

void scan_d ( int& x , char c = 0 , int flag = 0 ) {
    while ( ( c = getchar () ) != - && ( c < 0 || c > 9 ) ) ;
    if ( c == - ) flag = 1 , x = 0 ;
    else x = c - 0 ;
    while ( ( c = getchar () ) >= 0 && c <= 9 ) x = x * 10 + c - 0 ;
    if ( flag ) x = -x ;
}

void change(int x,int y,int c){
    int fx = top[x],fy = top[y];
    while(fx != fy){
        //cout<<1<<endl;
        if(dep[fx] < dep[fy]) swap(fx,fy),swap(x,y);
        sum[tid[fx]]+=c; sum[tid[x]+1] -= c;
        x = fa[fx]; fx = top[x];
    }
    if(dep[x] > dep[y]) swap(x,y);
    sum[tid[x]] += c;sum[tid[y]+1]-=c;
    return ;
}

void change1(int x,int y,int c){
    int fx = top[x],fy = top[y];
    while(fx != fy){
        if(dep[fx] < dep[fy]) swap(fx,fy),swap(x,y);
       sum1[tid[fx]]+=c,sum1[tid[x]+1]-=c;
        x = fa[fx]; fx = top[x];
    }
    if(dep[x] > dep[y]) swap(x,y);
    sum1[tid[fx]+1]+=c;sum1[tid[x]+1]-=c;
    return ;
}

void init(){
    memset(son,-1,sizeof(son));
    memset(sum,0,sizeof(sum));
    memset(sum1,0,sizeof(sum1));
    memset(siz,0,sizeof(siz));
    for(int i = 0;i <= n;i ++){
        e[i].to=0;e[i].next=0;head[i]=0;
    }
}
int main()
{
    int t,x,m,y,c,u[M],v[M];
    scan_d(t);
    int t1 = t;
    while(t--){
        init();
        scan_d(n);scan_d(m);
        cnt1 = 1;cnt = 1;
        for(int i = 0;i < n-1;i ++){
            scan_d(u[i]); scan_d(v[i]);
            add(u[i],v[i]);
        }
        dfs1(1,0,1);dfs2(1,1);
        char s[10];
        while(m--){
            scanf("%s",s);
            scan_d(x);scan_d(y);scan_d(c);
            if(s[3]==1)
                change(x,y,c);
            else
                change1(x,y,c);
        }
          printf("Case #%d:\n",t1-t);
            for(int i = 2;i <= n;i ++){
                sum[i] += sum[i-1];
                sum1[i] += sum1[i-1];
            }
            for(int i = 1;i <= n;i ++){
                if(i == n) printf("%lld\n",sum[tid[i]]);
                else printf("%lld ",sum[tid[i]]);
            }
            for(int i = 0;i < n-1;i ++){
                if(dep[u[i]] > dep[v[i]]) swap(u[i],v[i]);
                if(i != n-2)  printf("%lld ",sum1[tid[u[i]]]);
                else printf("%lld\n",sum1[tid[u[i]]]);
            }
    }
    return 0;
}

 

以上是关于hdu 5044 Tree (树链剖分+标记数组)的主要内容,如果未能解决你的问题,请参考以下文章

hdu6547Tree(树链剖分, 线段树区间根号)

POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)

POJ 3237 Tree(树链剖分)

(树链剖分+线段树)POJ - 3237 Tree

树链剖分模版

POJ3237Tree(树链剖分)