现在的位置: 首页 > 综合 > 正文

HDU – 5044(树链剖分)

2019年04月05日 ⁄ 综合 ⁄ 共 2719字 ⁄ 字号 评论关闭
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
const int maxn = 111111;

long long ADD1[maxn],ADD2[maxn];
int side,node,wei[maxn],link[maxn],lnode[maxn];

//先转化为有根树
int fa[maxn];  //每个结点的父节点
int w[maxn];  //每个结点的与其父节点的连边在线段树中的位置
int top[maxn]; //每条重链中其首节点;
int dep[maxn]; //每个节点的深度;
int son[maxn]; //每个节点的重儿子
int siz[maxn];
//vector<int> eson[maxn];

int tot,head[maxn*2];
 struct Edge{
      int to,next;
 }edge[maxn*2];
void addedge(int u,int v){
    edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;
}

void init_dfs(int u){
siz[u]=1; son[u]=0;
for(int i = head[u];i != -1; i = edge[i].next)if(edge[i].to!=fa[u]){
    int v=edge[i].to;
    fa[v]=u;
    dep[v]=dep[u]+1;
    init_dfs(v);
    if(siz[son[u]]< siz[v]) son[u]=v;
    siz[u]+=siz[v];
}
}

void build_tree(int u,int tp){
w[u]=side++; top[u]=tp;  wei[u]=node++;
if(son[u]!=0) {
       build_tree(son[u],tp);
}
for(int i = head[u];i != -1; i = edge[i].next)if(edge[i].to!=fa[u]&&edge[i].to!=son[u]){
    build_tree(edge[i].to,edge[i].to);
}
}

void init(int n){
for(int i=0;i<=n;i++) ADD1[i]=ADD2[i]=0;
fa[1]=1; dep[1]=0; top[1]=1;
init_dfs(1);
side=0; node=1;
build_tree(1,1);
}

int ql,qr,addv;
int find(int u,int v){
int f1=top[u],f2=top[v];
int res=0;
while(f1!=f2){
    if(dep[f1]<dep[f2]){
        swap(f1,f2); swap(u,v);
    }
    ql=w[f1]; qr=w[u]+1;
    ADD2[ql]+=addv;
    ADD2[qr]-=addv;
    u=fa[f1]; f1=top[u];
}
if(u==v) return res;
if(dep[u]<dep[v]) swap(u,v);
ql=w[son[v]]; qr=w[u]+1;
ADD2[ql]+=addv;
ADD2[qr]-=addv;
}

void find_node(int u,int v){
int f1=top[u],f2=top[v];
int res=0;
while(f1!=f2){
    if(dep[f1]<dep[f2]){
        swap(f1,f2); swap(u,v);
    }
    ql=wei[f1]; qr=wei[u]+1;
    ADD1[ql]+=addv;
    ADD1[qr]-=addv;
    u=fa[f1]; f1=top[u];
}
if(dep[u]<dep[v]) swap(u,v);
ql=wei[v]; qr=wei[u]+1;
ADD1[ql]+=addv;
ADD1[qr]-=addv;
}

template <class T>
inline bool scan_d(T &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;
}

inline void out(long long x) {
    if(x>9) out(x/10);
    putchar(x%10+'0');
}

int d[maxn][3];
int main()
{
    int T;
    int n,kase=1;
    scanf("%d",&T);
    while(T--){
        int Q;
        scan_d(n);
        scan_d(Q);
        int x,y,z;
        tot=0;  memset(head,-1,sizeof(head));
        for(int i=1;i<n;i++){
            scan_d(x);
            scan_d(y);
            d[i][0]=x; d[i][1]=y; d[i][2]=0;
            addedge(d[i][0],d[i][1]);
            addedge(d[i][1],d[i][0]);
        }
        init(n);
        for(int i=1;i<n;i++){
             if(dep[d[i][0]]>dep[d[i][1]]) swap(d[i][0],d[i][1]);
        }
        char cmd[100];
        while(Q--){
            int u,v;
            scanf("%s",cmd);
            scan_d(u);
            scan_d(v);
            scan_d(addv);
            if(cmd[3]=='1'){
                find_node(u,v);
            }
            else find(u,v);
        }
        for(int i=1;i<=n;i++){
            ADD1[i]+=ADD1[i-1];
            ADD2[i]+=ADD2[i-1];
        }
        printf("Case #%d:\n",kase++);
        for(int i=1;i<=n;i++){
            if(i!=1) printf(" ");
            out(ADD1[wei[i]]);
        }
        printf("\n");
        for(int i=1;i<n;i++){
            if(i!=1) printf(" ");
            out(ADD2[w[d[i][1]]]);
        }
        printf("\n");
    }
    return 0;
}

本题时间卡的很严;很多地方需注意,输入输出加挂,o(1)的改,o(1)的查,主题方法为树链剖分,实现邻接表的存储用链表形式

抱歉!评论已关闭.