【北京集训D2T3】tvt

【北京集训D2T3】tvt



\(n,q \le 1e9\)

题目分析:

首先需要对两条路径求交,对给出的四个点的6个lca进行分类讨论。易于发现路径的交就是这六个lca里面最深的两个所形成的链。

然后即可再分两种情况进行讨论。

对于同向的路径,我们可以求出到达交的起点的时间差,然后与链上的最长边进行比较,如果大于说明可行。

对于对向的路径,如果能在时间差内走到交集上,同时不是在一个顶点相遇那么一定就是合法情况,否则就是不合法情况。这部分可以用倍增解决。

#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5+7;
#define ll long long
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
struct po{
    int nxt,to;
    ll dis;
}edge[MAXN<<1];
ll head[MAXN],n,m,u1,v1,t1,u2,v2,t2,st[MAXN<<2],size[MAXN],fa[MAXN],dep[MAXN],top[MAXN],id[MAXN],w[MAXN],val[MAXN],wson[MAXN];
ll cnt,num,mx[MAXN<<2];
inline void pushup(int rt){st[rt]=st[ls]+st[rs];mx[rt]=max(mx[ls],mx[rs]);}
inline void dfs1(int u,int f)
{
    size[u]=1;fa[u]=f;dep[u]=dep[f]+1;
    for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==f) continue;
        val[v]=edge[i].dis;
        dfs1(v,u);
        size[u]+=size[v];
        if(size[wson[u]]<size[v]) wson[u]=v;
    }
}
inline void dfs2(int u,int tp)
{
    id[u]=++cnt;top[u]=tp;w[cnt]=val[u];
    if(wson[u]) dfs2(wson[u],tp);
    for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v==fa[u]||v==wson[u]) continue;
        dfs2(v,v);
    }
}
void build(int l,int r,int rt)
{
     if(l==r){
        st[rt]=mx[rt]=w[l];
        return;
     }
     build(l,mid,ls);build(mid+1,r,rs);
     pushup(rt);
     return;
}
ll query_max(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R) return mx[rt];
    ll maxx=0;
    if(L<=mid) maxx=max(maxx,query_max(L,R,l,mid,ls));
    if(R>mid) maxx=max(maxx,query_max(L,R,mid+1,r,rs));
    return maxx;
}
ll query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R) return st[rt];
    ll sum=0;
    if(L<=mid) sum+=query(L,R,l,mid,ls);
    if(R>mid) sum+=query(L,R,mid+1,r,rs);
    return sum;
}
inline int find(int x,int y)
{
    while(top[x]!=top[y]){
        if(dep[top[x]]>dep[top[y]]) x=fa[top[x]];
        else y=fa[top[y]];
    }
    if(dep[x]>dep[y]) return y;
    else return x;
}
inline ll Query_max(int x,int y)
{
    ll maxx=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        maxx=max(maxx,query_max(id[top[x]],id[x],1,n,1));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    if(x!=y) maxx=max(maxx,query_max(id[x]+1,id[y],1,n,1));
    return maxx;
}
inline ll Query(int x,int y)
{
    ll ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans+=query(id[top[x]],id[x],1,n,1);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    ans+=query(id[x],id[y],1,n,1);
    return ans;
}
inline void add_edge(int from,int to,ll dis)
{
    edge[++num].nxt=head[from];
    edge[num].to=to;
    edge[num].dis=dis;
    head[from]=num;
}
inline ll read()
{
    ll x=0,c=1;
    char ch=' ';
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    while(ch=='-')c*=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*c;
}
int main()
{
//  freopen("data.in","r",stdin);
//  freopen("my.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<n;i++){
        int x,y,z;
        x=read();y=read();z=read();
        add_edge(x,y,z);add_edge(y,x,z);
    }
    dfs1(1,1);dfs2(1,1);
    build(1,n,1);
    while(m--){
        u1=read();v1=read();t1=read();u2=read();v2=read();t2=read();
        int lca1=find(u1,v1),lca2=find(u2,v2);
        if(dep[lca1]<dep[lca2]){
            swap(u1,u2);swap(v1,v2),swap(t1,t2);swap(lca1,lca2);
        }
        if(find(lca1,u2)!=lca1&&find(lca1,v2)!=lca1){
            puts("NO");
            continue;
        }
        int lca3=find(u1,u2),lca4=find(v1,v2);
        if(dep[lca1]<dep[lca3]){
            ll cnt1=Query(u1,lca3)+t1-val[find(u1,lca3)],cnt2=Query(u2,lca3)-val[find(u2,lca3)]+t2;
            if(dep[lca1]>dep[lca4]) lca4=lca1;
            int maxx=Query_max(lca3,lca4);
            if(abs(cnt1-cnt2)<maxx) puts("YES");
            else puts("NO");
            continue;
        }
        if(dep[lca1]<dep[lca4]){
            if(dep[lca3]<dep[lca1]) lca3=lca1;
            ll cnt1=Query(u1,lca3)-val[find(u1,lca3)]+t1,cnt2=Query(u2,lca3)-val[find(u2,lca3)]+t2;
//          cout<<cnt1<<" "<<cnt2<<endl;
            int maxx=Query_max(lca3,lca4);
            if(abs(cnt1-cnt2)<maxx) puts("YES");
            else puts("NO");
            continue;
        }
        int lca5=find(u1,v2),lca6=find(u2,v1);
        if(dep[lca5]<dep[lca1]) lca5=lca1;
        if(dep[lca6]<dep[lca1]) lca6=lca1;
        ll cnt1=Query(u1,lca5)+t1-val[find(u1,lca5)],cnt2=Query(u2,lca6)+t2-val[find(u2,lca6)],cnt3=Query(lca5,lca6)-val[find(lca5,lca6)];
        ll cnt4=abs(cnt1-cnt2);
        if(cnt4>=cnt3){
            puts("NO");
            continue;
        }else{
            ll pass=(cnt3-cnt4)/2;
            if(pass!=(cnt3-cnt4)/2.0){
                puts("YES");
                continue;
            }
            if(cnt1>cnt2){
                ll cnt5=Query(lca5,lca1)-val[lca1];
                if(pass==cnt5){
                    puts("NO");
                    continue;
                }
                if(pass>cnt5){
                    pass+=cnt4;
                    while(pass-val[lca6]>=0){
                        pass-=val[lca6];
                        lca6=fa[lca6];
                    }
                    if(pass==0) puts("NO");
                    else puts("YES");
                } else {
                    while(pass-val[lca5]>=0){
                        pass-=val[lca5];
                        lca5=fa[lca5];
                    }
                    if(pass==0) puts("NO");
                    else puts("YES");
                }
            } else {
                ll cnt6=Query(lca6,lca1)-val[lca1];
                if(pass==cnt6){
                    puts("NO");
                    continue;
                }
                if(pass>cnt6){
                    pass+=cnt4;
                    while(pass-val[lca5]>=0){
                        pass-=val[lca5];
                        lca5=fa[lca5];
                    }
                    if(pass==0) puts("NO");
                    else puts("YES");
                } else {
                    while(pass-val[lca6]>=0){
                        pass-=val[lca6];
                        lca6=fa[lca6];
                    }
                    if(pass==0) puts("NO");
                    else puts("YES");
                }
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/victorique/p/10145051.html

时间: 2024-10-06 08:16:46

【北京集训D2T3】tvt的相关文章

【2016北京集训测试赛(八)】 crash的数列

Description 题解 题目说这是一个具有神奇特性的数列!这句话是非常有用的因为我们发现,如果套着这个数列的定义再从原数列引出一个新数列,它居然还是一样的...... 于是我们就想到了能不能用多点数列套着来加速转移呢? 但是发现好像太多数列套起来是可以烦死人的...... 我们就采用嵌套两次吧,记原数列为A,第一层嵌套为B,第二层嵌套为C. 我们其实可以发现一些规律,对于Ci,它对应了B中i的个数:对于Bi,它对应了A中i的个数. 稍加处理即可,我们一边计算一边模拟数列的运算,同时可以计算

学习总结——北京集训

时间过得快啊····刚来的时候还觉得度日如年,结果习惯后一晃眼集训就完了. 其实集训开始前我是死都不想去的,毕竟耽误一个月文化课,最终在家长老师的逼迫和劝说下还是去了··主要是一个老师劝我的时候有些事情说到我点子上了. 后来就被赶去集训了···经过30天的学习,包括19场考试的洗礼,发现收获真的很多.人生有些事情都是这样吧··在做之前永远不知道会经历什么,只有认真对待才会有所收获,所以下次面对这些事情再也不会纠结了,因为有些事情是没有对错的,做好了这些事情就不会亏... 另外眼界也开拓了许多啊·

[北京集训测试赛(三)]灯(Light)-奇怪乱搞数学题-素数

Problem 灯 题目大意 n盏灯排成一列,标号一到n,一开始标号为1的灯亮着. 现在依次对于2~n的每一个质数pi,指定一盏亮着的灯ai,点亮所有标号为$A[i]\pm kP_i$的灯. 有spj,任意一种方案即可. 输入一个整数n,输出点灯方案. Solution 首先写个暴力,考虑一下小范围的数据. 我们发现$n<16$的时候没有完美解,都是n-1.再算下去,发现$n>16$的时候任意一组都有完美解. 我们分析一下这个玩意儿. 把一到n的灯集体下标前移1,变成0~n-1.这时候当我们点

北京集训TEST16——图片加密(fft+kmp)

题目: Description CJB天天要跟妹子聊天,可是他对微信的加密算法表示担心:"微信这种加密算法,早就过时了,我发明的加密算法早已风靡全球,安全性天下第一!" CJB是这样加密的:设CJB想加密的信息有 m 个字节.首先,从网上抓来一张 n(n≥m) 个字节的图片,分析里面的每个字节(byte).每个字节有8位(bit)二进制数字.他想替换掉某些字节中最低位的二进制数字,使得这张图片中,连续 m 个字节恰为他想加密的信息.这样,图片看起来没什么区别,却包含了意味深长的信息.

【2016北京集训测试赛(八)】直径

注意:时限更改为4s 题解 考虑最原始的直径求法:找到离根节点(或离其他任意一点)最远的节点far1,再从far1出发找到离far1最远的节点far2,far1至far2的距离即为直径. 题目中提到了将原树的子树复制成新子树这一操作,显然如果我们将子树真正复制出来是会爆炸的. 实际上我们可以将每棵新子树中,真正有用的节点提取出来,以简化每个子树的结构,再按照题目的要求连接各个新子树. 我们用虚树来重构每一棵子树.每棵子树的虚树的关键点应至少包含: 子树的根节点. 这棵子树内部的直径的两端节点.

【2016北京集训测试赛(七)】自动机 (思考题)

Time Limit: 1000 ms Memory Limit: 256 MB Description Solution 这是一道看起来令人毫无头绪的题,然而确实十分简单巧妙TAT. 题目要求所有点执行相同指令后都回到初始状态. 我们先来考虑只有两种状态的情况:初始状态$T_0$与另一个状态$T_x$. 这样,我们可以通过一个二元记忆化深搜,来得到一种方案A,使得$T_0$回到$T_0$,且$T_x$回到$T_0$.如果这个方案都不存在,那么此时无解. 现在我们知道,执行方案A后,$T_x$与

[北京集训测试赛(五)/HDU5299]圆圈游戏(Circles game)-树上删边-圆的扫描线

Problem 遗产 题目大意 一个平面上n个圆,任两个圆只会相离或包含,给出每个圆位置与半径. alice&&bob轮流取圆,每取一个就可以取出这个圆以及被这个圆包含的圆. 没圆取的人输,alice先取,问谁有必胜策略. Solution Method #1 首先我们考虑一个暴力一点的写法: 先将圆半径从小到大排序,然后枚举两个圆,判断是否包含关系. 如果包含的话就将大圆连一条边到小圆. 很容易发现,这样执行完以后得到了一棵树. 我们接下来要做的事情就变成了: 每个人可以轮流从树上删除一

【2016北京集训测试赛】river

HINT 注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式. [吐槽] 嗯..看到这题的想法的话..先想到了每个点的度为2,然后就有点不知所措了 隐隐约约想到了网络流,但并没有继续往下想了... 听完学长的讲评之后(%xj)个人觉得建图还是很有意思的ovo [题解] 因为每个点到对面都有k种方式,那就想到每个点原来的点$x_0$拆成k个点$x_1$, $x_2$, $x_3$... $x_k$ 然后很自然地$x_0$和拆成的点之间要连边 容量的话,因为hint里面的限制

北京集训TEST13——PA(Goodness)

题目: Description 桌面上放有 n 张卡牌.对于每张卡牌,一面是绿色的,另一面是红色的.卡牌的每一面都标有一个整数.对于卡牌a和卡牌b,卡牌a对卡牌b的好感度为卡牌a绿色面的数与卡牌b红色面的数的乘积. 举个例子,如果卡牌a绿色面标有10,红色面标有3:卡牌b绿色面标有7,红色面标有-2.那么a对b的好感度为 10×(?2)=?20 ,b对a的好感度为 7×3=21 .则a和b的好感度的差异为 |21?(?20)|=41 . 现在,你知道这 n 张卡牌每一面的数,请你找出两张卡牌,使