欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

DAY5测试T2 Tree(LCA+线段树/树上差分)

程序员文章站 2022-07-12 17:58:32
...

【问题描述】
小s是A星球的霸主。A星球上有n个城市,城市之间有一些道路。小s发现城市和道路刚好组成了一棵树。并且他发现如果有任意一条道路损坏,城市和城市之间就不连通了。A星球上还有m对工作站(A, B)。每对工作站在工作的时候,需要人员从A城市走到B城市。
现在A星球有Q个任务,每个任务可以由第L对工作站到第R对工作站任意一个来完成。小s想知道对于每个任务,损坏了哪些边会导致任务不能完成。他想把这个问题交给你,但你只需要告诉他损坏的边的总长度即可。
【输入格式】
输入的第一行包含1个整数n,表示城市个数。
接下来n-1行,每行包含3个整数x, y, z,表示边(x, y)和边的长度z。
接下来一行一个整数m,表示m对工作站。
接下来m行,每行包含两个整数A, B
接下来一行一个整数Q,表示任务数。
接下来Q行,每行两个整数L,R。表示第i个任务可以由第L对到第R对工作站完成。
【输出格式】
输出Q行,第i行表示第i个任务的答案。
【样例输入】
4
1 2 5
2 3 2
1 4 3
2
1 2
3 4
1
1 2
【样例输出】
5
【数据范围与约定】
30%: n, m, Q <= 200
60%: n, m, Q <= 1000
100%: n, m, Q <= 50000


一看到题就想起之前做的NOIP2015 运输计划了。简化题意为求第L~R条给定路径公共边的权值和。那么跑一遍dfs预处理出 dis[ i ] 数组表示节点 i 到根节点的距离,则可得每对工作站的路径长。
然后开始读入查询,对于每对查询都做一遍差分。差分数组为 dif 。例如对于某对工作站 ( x, y ),dif [ x ]+=1, dif [ y ]+=1 ,dif[ LCA( x, y ) ]-=2。处理完 [ L,R ] 后求一遍子树权值和。若某个点权值和等于 R-L+1 ,则其到父节点的那条边必为公共边。由于倍增求LCA中会处理出数组 f[ x][ 0 ],故易得其父节点。枚举 n 求和即可。
时间复杂度大致是 O( nq ),能过六十分。但是要开long long。以后这种累加的都应该注意一点。

正解很绝妙。
通过观察可以发现对于两条路径:(x1,y1)和(x2,y2),在LCA(x1,x2),LCA(x1,y2),LCA(y1,x2),LCA(y1,y2)中取深度最大的两个点,这两点之间的路径即为公共路径。画个图就能明白。
这么说题目暗示还是给的很明显的,“第L对到第R对”,还有这么大的查询量,肯定要用数据结构维护了。我们考虑线段树。
用线段树维护 1~m 对工作站。每段区间(x,y)都表示第 x 对~第 y 对按上述方法求出的公共路径的两个端点。剩下都是线段树的常规操作。

调了很久……居然是因为忘记删一个比较微妙的打表。

#include<bits/stdc++.h>
using namespace std;

const int maxn=50001;

int n,m,q;
int x,y,z;
int Link[maxn];
struct edge{
    int y,next,v;
}e[maxn<<1];
int Tot;

int dep[maxn];
long long dis[maxn];
int f[maxn][30];
bool vis[maxn];
int K;

struct Node{
    int N1,N2;
}Tree[maxn<<2],Temp2,Res;
int L,R;
int Temp1[4];

inline void read(int &x)
{
    x=0;int f=1;char s=getchar();
    for(;s<'0'||s>'9';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=(x<<3)+(x<<1)+s-48;
    x*=f;
} 

inline void Insert(int x,int y,int v)
{
    e[++Tot].y=y;e[Tot].v=v;
    e[Tot].next=Link[x];Link[x]=Tot;
}

inline bool mycmp(int a,int b)
{
    return(dep[a]>dep[b]);
}

int get_LCA(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=K;i>=0;--i)
        if(dep[x]-(1<<i)>=dep[y]) x=f[x][i];
    if(x==y) return x;
    for(int i=K;i>=0;--i)
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}

inline Node Unite(Node a,Node b)
{

    Temp1[0]=get_LCA(a.N1,b.N1);Temp1[1]=get_LCA(a.N1,b.N2);
    Temp1[2]=get_LCA(a.N2,b.N1);Temp1[3]=get_LCA(a.N2,b.N2);
    sort(Temp1,Temp1+4,mycmp);
    Temp2.N1=Temp1[0];Temp2.N2=Temp1[1];
    return Temp2;
}//合并。

void dfs_mul(int x)
{
    vis[x]=1;
    for(int i=1;(1<<i)<=dep[x];++i) f[x][i]=f[f[x][i-1]][i-1];
    for(int i=Link[x];i;i=e[i].next)
        if(!vis[e[i].y]){
            dep[e[i].y]=dep[x]+1;dis[e[i].y]=dis[x]+1LL*e[i].v;f[e[i].y][0]=x;
            dfs_mul(e[i].y);
        }
}

void Build(int Root,int l,int r)
{
    if(l==r){
        read(Tree[Root].N1);read(Tree[Root].N2);
        return;
    }
    int Mid=(l+r)>>1;
    Build(Root<<1,l,Mid);Build(Root<<1|1 ,Mid+1,r);
    Tree[Root]=Unite(Tree[Root<<1],Tree[Root<<1|1]);
}

Node Query(int Root,int l,int r)
{
    if(L<=l&&r<=R) return Tree[Root];
    int Mid=(l+r)>>1;
    if(L>Mid) return Query(Root<<1|1,Mid+1,r);
    else if(R<=Mid) return Query(Root<<1,l,Mid);
    else return Unite(Query(Root<<1,l,Mid),Query(Root<<1|1,Mid+1,r)); 
}

void Init()
{
    read(n);
    Tot=0;
    for(int i=1;i<n;++i) 
    {
        read(x);read(y);read(z);
        Insert(x,y,z);Insert(y,x,z); 
    }
}

void Prepare()
{
    memset(vis,0,sizeof(vis));
    memset(dep,0,sizeof(dep));
    memset(f,0,sizeof(f));
    memset(dis,0,sizeof(dis));
    dep[1]=1;f[1][0]=-1;
    dfs_mul(1);
    K=(int)(log(n)/log(2))+1;
    read(m);
    Build(1,1,m);
}

void Work()
{
    read(q);
    for(int i=1;i<=q;++i)
    {
        read(L);read(R);
        Res=Query(1,1,m); 
        printf("%lld\n",1LL*dis[Res.N1]+1LL*dis[Res.N2]-1LL*(dis[get_LCA(Res.N1,Res.N2)]<<1));
    }
}

int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    Init();
    Prepare();
    Work();
    fclose(stdin);fclose(stdout);
    return 0;
}

这几天唯一一道确定能拿到部分分的题,居然因为 long long 的问题挂掉了。非常不应该。太久了都没有概念了啊。