2021牛客暑期多校训练营2

比赛链接:https://ac.nowcoder.com/acm/contest/11253

第一场有事没打;第二场暑训正式开始。C,D,F,K,4/12,垫底了,咳。G记录得比较详细,我就不回忆了。

改了两天题:

A:Arithmetic Progression

题意:

给一个序列 \( a \) ,求其所有满足 排序后是等差数列 的子区间的个数。\( 1 \leq n \leq 10^5 \) , \( 1 \leq a_i \leq 10^9 \) , \( a_i \) 各不相同。

分析:

快速判定子区间 \( \left [ l,r \right ) \) 满足条件的方法:若排序后为等差数列,则公差 \( d = gcd\left ( b_{l+1}-b_1 , b_{l+2}-b_{l+1} , ... , b_r-b_{r-1} \right ) \) ;

那么判定条件就可以是 \( max\left \{ a_l , ... , a_r \right \} - min\left \{ a_l , ... , a_r \right \} = ( r-l ) * gcd\left ( b_{l+1}-b_l , b_{l+2}-b_{l+1} , ... , b_r-b_{r-1} \right ) \) ,而且可以发现 \( max\left \{ a_l , ... , a_r \right \} - min\left \{ a_l , ... , a_r \right \} \) 一定大于等于 \( ( r-l ) * gcd\left ( b_{l+1}-b_l , b_{l+2}-b_{l+1} , ... , b_r-b_{r-1} \right ) \) ;

所以可以考虑枚举 \( r \) ,再 \( log(n) \) 维护\( max \) , \( min \) 和 \( gcd \);

上式写成 \( max\left \{ a_l , ... , a_r \right \} - min\left \{ a_l , ... , a_r \right \} + l * gcd = r * gcd \) ,用线段树来维护 \( max\left \{ a_l , ... , a_r \right \} - min\left \{ a_l , ... , a_r \right \} + l * gcd \) 的最小值以及是这个最小值的点的个数;\( max \) 和 \( min \) 可以结合单调栈维护,进行区间修改;\( gcd \) 直接单点修改,但是对于每个 \( l \) ,这个点上存的 \( gcd \) (初值 \( a_{l+1}-a_l\) )最多修改 \( log(n) \) 次,所以复杂度是 \( nlog(n) \);每个 \( r \) 处找一遍答案,也就是看看最小值和上式右面是否相等,相等的话就把答案加到个数里。

代码如下:

#include<iostream>
#define ll long long
#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((l+r)>>1)
using namespace std;
int const N=1e5+5;
ll const INF=1e17;
int n,tpmn,tpmx,cnt;
ll a[N],qmn[N],qmx[N],g[N],gpos[N],ans;
struct Nd{
    ll s,tg,cnt,mn;
}tr[N<<2];
struct qNd{
    ll mn,num;
};
ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
ll ab(ll x){return x>0?x:-x;}
void pdn(int u)
{
    if(!tr[u].tg)return;
    ll s=tr[u].tg; tr[u].tg=0;
    tr[ls].tg+=s; tr[ls].mn+=s;
    tr[rs].tg+=s; tr[rs].mn+=s;
}
void upt(int u)
{
    //printf("upt(%d):ls.mn=%lld rs.mn=%lld\n",u,tr[ls].mn,tr[rs].mn);
    if(tr[ls].mn<tr[rs].mn)tr[u].mn=tr[ls].mn,tr[u].cnt=tr[ls].cnt;
    if(tr[ls].mn==tr[rs].mn)tr[u].mn=tr[ls].mn,tr[u].cnt=tr[ls].cnt+tr[rs].cnt;
    if(tr[ls].mn>tr[rs].mn)tr[u].mn=tr[rs].mn,tr[u].cnt=tr[rs].cnt;
}
void init(int u,int l,int r)
{
    tr[u].mn=INF; tr[u].tg=0; tr[u].cnt=r-l+1;
    if(l==r)return;
    //printf("u=%d ls=%d rs=%d l=%d r=%d mid=%d\n",u,ls,rs,l,r,mid);
    init(ls,l,mid); init(rs,mid+1,r);
}
void add(int u,int l,int r,int ql,int qr,ll s)
{
    //printf("add(u=%d l=%d r=%d ql=%d qr=%d s=%lld\n",u,l,r,ql,qr,s);
    if(l>=ql&&r<=qr){tr[u].tg+=s; tr[u].mn+=s; return;}
    pdn(u);
    if(mid>=ql)add(ls,l,mid,ql,qr,s);
    if(mid<qr)add(rs,mid+1,r,ql,qr,s);
    upt(u);
    //printf("upt:u=%d l=%d r=%d mn=%d cnt=%d\n",u,l,r,tr[u].mn,tr[u].cnt);
}
qNd qry(int u,int l,int r,int ql,int qr)
{
    //printf("qry:u=%d l=%d r=%d ql=%d qr=%d\n",u,l,r,ql,qr);
    if(l>r||ql>qr)return (qNd){-1,0};
    if(l>=ql&&r<=qr)return (qNd){tr[u].mn,tr[u].cnt};
    //printf("qry:pdn(%d)\n",u);
    pdn(u);
    if(mid>=qr)return qry(ls,l,mid,ql,qr);
    if(mid<ql)return qry(rs,mid+1,r,ql,qr);
    //upt(u);
    qNd qls=qry(ls,l,mid,ql,qr),qrs=qry(rs,mid+1,r,ql,qr),ret=qls;
    if(qls.mn>qrs.mn)ret=qrs;
    else if(qls.mn==qrs.mn)ret.num+=qrs.num;
    return ret;
}
int main()
{
    int T; scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n); init(1,1,n); ans=0; cnt=0; tpmn=0; tpmx=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]); //printf("i=%d\n",i);
            while(tpmn&&a[qmn[tpmn]]>=a[i])add(1,1,n,qmn[tpmn-1]+1,qmn[tpmn],a[qmn[tpmn]]),tpmn--;
            add(1,1,n,qmn[tpmn]+1,i,-a[i]); qmn[++tpmn]=i;
            while(tpmx&&a[qmx[tpmx]]<=a[i])add(1,1,n,qmx[tpmx-1]+1,qmx[tpmx],-a[qmx[tpmx]]),tpmx--;
            add(1,1,n,qmx[tpmx]+1,i,a[i]); qmx[++tpmx]=i;
            if(i==1)continue;//
            g[++cnt]=ab(a[i]-a[i-1]); gpos[cnt]=i-1;
            add(1,1,n,i-1,i-1,(ll)(i-1)*g[cnt]-INF);//-INF!
            for(int k=cnt-1;k;k--)
                if(g[k+1]%g[k])
                {
                    ll pre=g[k]; g[k]=gcd(g[k+1],g[k]);//
                    for(int p=gpos[k];p<gpos[k+1];p++)add(1,1,n,p,p,(ll)p*(g[k]-pre));
                }
            //printf("cnt=%d\n",cnt);
            //for(int i=1;i<=cnt;i++)printf("g[%d]=%d ",i,g[i]); printf("\n");
            int num=0;
            for(int i=1;i<=cnt;i++)
                if(g[i]!=g[i-1])g[++num]=g[i],gpos[num]=gpos[i];
            cnt=num;
            //printf("cnt2=%d\n",cnt);
            //for(int i=1;i<=cnt;i++)printf("g[%d]=%d ",i,g[i]); printf("\n");
            for(int k=1;k<=cnt;k++)//一个,两个数也是
            {
                //printf("gpos[%d]=%d\n",k,gpos[k]);
                qNd t=qry(1,1,n,gpos[k],(k==cnt)?i-1:gpos[k+1]-1);
                //printf("qry.mn=%lld qry.num=%lld i*g=%lld\n",t.mn,t.num,(ll)i*g[k]);
                if(t.mn==(ll)i*g[k])ans+=t.num;
            }
        }
        printf("%lld\n",ans+n);
    }
    return 0;
}
me

 

C:Draw Grids

题意:

给定一个 \( n * m \) 的点阵,每次选两个相邻点连线,不能连出封闭图形,两人轮流操作,不能操作者输。

分析:

不能形成环,所以终态是一棵树,所以可以根据点数的奇偶性判断。

签到题,Y做了,G写了。

#include<bits/stdc++.h>
using namespace std;
int n,m;
int main()
{   scanf("%d%d",&n,&m);
    if((n==1||n==3)&&(m==1||m==3)) puts("NO");
    else puts("YES");
}
Y&G

 

D:Er Ba Game

题意+分析:

按照题意模拟即可。

签到题,G写了。

#include<bits/stdc++.h>
using namespace std;
int T,A1,B1,A2,B2,Flag;
int main()
{   for(scanf("%d",&T);T;T--)
    {   scanf("%d%d%d%d",&A1,&B1,&A2,&B2),Flag=0;
        if(A1>B1) swap(A1,B1);
        if(A2>B2) swap(A2,B2);
        if(A1==A2&&B1==B2&&!Flag) puts("tie"),Flag=1;
        if(A1==2&&B1==8&&!Flag) puts("first"),Flag=1;
        if(A2==2&&B2==8&&!Flag) puts("second"),Flag=1;
        if(A1==B1&&A2==B2&&A1>A2&&!Flag) puts("first"),Flag=1;
        if(A2==B2&&A1==B1&&A2>A1&&!Flag) puts("second"),Flag=1;
        if(A1==B1&&A2!=B2&&!Flag) puts("first"),Flag=1;
        if(A2==B2&&A1!=B1&&!Flag) puts("second"),Flag=1;
        if((A1+B1)%10>(A2+B2)%10&&!Flag) puts("first"),Flag=1;
        if((A2+B2)%10>(A1+B1)%10&&!Flag) puts("second"),Flag=1;
        if(B1>B2&&!Flag) puts("first"),Flag=1;
        if(B2>B1&&!Flag) puts("second"),Flag=1;
    }
}
G

 

F:Girlfriend

题意:

空间内有六个点:定点 \( A, B, C, D \) ,动点 \( P_1, P_2 \) ,满足 \( |P_1A| \geq k_1|P_1B| , |P_2C| \geq k_2|P_2D| \) , 求 \( P_1, P_2 \) 各自活动区域的交的体积。

分析:

容易发现 \( P_1, P_2 \) 各自的活动区域都是一个球(阿波罗尼斯球),可以求出球心坐标和半径;所以就是求两个球相交部分的体积。

可以分成两边来算;先用余弦定理求出球心到两球切面的距离,再积分一下即可。

YG写了。

#include<bits/stdc++.h>
#define N 200010
using namespace std;
const double pi=acos(-1);

int T;
double X1,X2,X3,X4,X5,Y1,Y2,Y3,Y4,Y5,z1,z2,z3,z4,z5,r1,r2,d,k1,k2,X6,Y6,z6,ans;
double read()
{   int a=0,c=1;   char b=getchar();
    while(b!='-'&&b<'0'||b>'9') b=getchar();
    if(b=='-') c=-1,b=getchar();
    while(b>='0'&&b<='9') a=a*10+b-48,b=getchar();
    return a*c*1.0;
}

double ask(double x, double y){
    return pi*(y*y*(y-x)-y*y*y/3+x*x*x/3);
}
int main(){
    scanf("%d",&T);
    while(T--){
        X1=read(),Y1=read(),z1=read();
        X2=read(),Y2=read(),z2=read();
        X3=read(),Y3=read(),z3=read();
        X4=read(),Y4=read(),z4=read();
        k1=read(),k2=read();
        X5=(X2*k1*k1-X1)/(k1*k1-1);
        Y5=(Y2*k1*k1-Y1)/(k1*k1-1);
        z5=(z2*k1*k1-z1)/(k1*k1-1);
        X6=(X4*k2*k2-X3)/(k2*k2-1);
        Y6=(Y4*k2*k2-Y3)/(k2*k2-1);
        z6=(z4*k2*k2-z3)/(k2*k2-1);
        r1=sqrt( ((X2*k1*k1-X1)*(X2*k1*k1-X1)+(k1*k1-1)*(X1*X1-k1*k1*X2*X2))*1.0/((k1*k1-1)*(k1*k1-1)) +
                 ((Y2*k1*k1-Y1)*(Y2*k1*k1-Y1)+(k1*k1-1)*(Y1*Y1-k1*k1*Y2*Y2))*1.0/((k1*k1-1)*(k1*k1-1)) +
                 ((z2*k1*k1-z1)*(z2*k1*k1-z1)+(k1*k1-1)*(z1*z1-k1*k1*z2*z2))*1.0/((k1*k1-1)*(k1*k1-1)) );
        r2=sqrt( ((X4*k2*k2-X3)*(X4*k2*k2-X3)+(k2*k2-1)*(X3*X3-k2*k2*X4*X4))*1.0/((k2*k2-1)*(k2*k2-1)) +
                 ((Y4*k2*k2-Y3)*(Y4*k2*k2-Y3)+(k2*k2-1)*(Y3*Y3-k2*k2*Y4*Y4))*1.0/((k2*k2-1)*(k2*k2-1)) +
                 ((z4*k2*k2-z3)*(z4*k2*k2-z3)+(k2*k2-1)*(z3*z3-k2*k2*z4*z4))*1.0/((k2*k2-1)*(k2*k2-1)) );
        d=sqrt((X5-X6)*(X5-X6) + (Y5-Y6)*(Y5-Y6) + (z5-z6)*(z5-z6));
        if(d>r1+r2){
            ans=0.0;
        }else{
            double mi=r1<r2?r1:r2;
            double ma=r1>r2?r1:r2;
            if(d+mi<ma){
                ans=4.0/3*pi*mi*mi*mi;
            }
            else{
                double h=(r1*r1-r2*r2+d*d)*1.0/(2*d);
                //ans=2*(4.0/3*pi*r1*r1*r1*2*acos(h/r1)/(2*pi) - pi*(r1*r1-h*h)*h/3);
                //ans=(4.0/3*pi*r1*r1*r1*2*acos(h/r1)/(2*pi) - pi*(r1*r1-h*h)*h/3)+(4.0/3*pi*r2*r2*r2*2*acos((d-h)/r2)/(2*pi) - pi*(r2*r2-(d-h)*(d-h))*(d-h)/3);
                ans=ask(h,r1)+ask(d-h,r2);
            }
        }
        printf("%.3lf\n",ans);
    }
    return 0;
}
Y&G

 

G:League of Legends

题意:

给定 \( n \) 个区间 \( \left [ a_i , b_i \right ) \),要求将它们分成 k 组,最大化每组交的长度之和。\( 1 \leq k \leq n \leq 5000 \) , \( 1 \leq a < b < 10^5 \) 。

分析:

对于内部完全包含某区间的一个大区间,其最优决策有两种:1.和它包含的那个区间同组,不影响答案;2.自己单独一组。想原因的话,可以把大区间当做最后一个加入的区间(反正没有顺序);它加入以后如果要组队,答案不增,所以最优的方案就是让答案不变,所以一种最优的组队方法就是和包含的那个区间同组。

然后就可以去掉这些大区间了,它们的贡献最后适当加一下即可。

现在剩下的区间就都是首尾相交的了,可以左端点递增排个序,然后DP, \( f[i][j] \) 表示前 \( i \) 个区间分了 \( j \) 组;那么转移的时候需要找一个地方分出最后一组,这里就可以用单调队列优化了。(但是连这也忘了所以专门看了看单调队列优化DP囧)

然后时间复杂度是\( O(n^2) \)。

代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int const N=5005;
int n,bm,m,K,b[N],f[N][N],q[N],ans;
struct Nd{
    int l,r;
    bool operator < (const Nd a) const{
        return l!=a.l?l<a.l:r>a.r;
    }
}a[N];
bool cmp(int a,int b){return a>b;}
int main()
{
    scanf("%d%d",&n,&K);
    for(int i=1;i<=n;i++)scanf("%d%d",&a[i].l,&a[i].r);
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)
    {
        bool fl=0;
        for(int j=i+1;j<=n;j++)
            if(a[j].r<=a[i].r){b[++bm]=a[i].r-a[i].l; fl=1; break;}
        if(!fl)a[++m]=a[i];
    }
    sort(b+1,b+bm+1,cmp);
    for(int i=2;i<=bm;i++)b[i]+=b[i-1];
    memset(f,255,sizeof f);
    f[0][0]=0;
    for(int j=1;j<=K;j++)
    {
        int hd=1,tl=0;
        for(int i=1;i<=m;i++)
        {
            if(f[i-1][j-1]>=0)//
            {
                while(hd<=tl&&f[q[tl]][j-1]+a[q[tl]+1].r<=f[i-1][j-1]+a[i].r)tl--;
                q[++tl]=i-1;
            }
            while(hd<=tl&&a[q[hd]+1].r<=a[i].l)hd++;//
            if(hd<=tl)f[i][j]=f[q[hd]][j-1]+a[q[hd]+1].r-a[i].l;//
        }
        if(bm>=K-j&&f[m][j]>=0)ans=max(ans,f[m][j]+b[K-j]);//
        //printf("f[%d][%d]=%d ans=%d\n",m,j,f[m][j],ans);
    }
    printf("%d\n",ans);
    return 0;
}
me

 

I:Penguins

题意:

给出左右两张 \( 20*20 \) 的图(有平地和障碍),两只企鹅分别从指定起点出发去指定终点,而且它们的走法是镜像的。输出最短步数、走法和有路径的图。

分析:

就是BFS。但我在比赛时没写好存储路径的地方。G改了半天,没改好。然后这题没过。

后来G改好了。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=22;
struct POS{
    int X1,Y1,X2,Y2,K;
    POS operator + (POS S)
    {   return (POS){X1+S.X1,Y1+S.Y1,X2+S.X2,Y2+S.Y2,K+S.K};   }
    bool operator == (POS S)
    {   return X1==S.X1&&X2==S.X2&&Y1==S.Y1&&Y2==S.Y2&&K==S.K;   }
}Last[MAXN][MAXN][MAXN][MAXN],Zero,St,End,L,R,U,D;
char M1[MAXN][MAXN],M2[MAXN][MAXN],Ans[500];
int As;
queue<POS>Team;
void Prepare()
{   L=(POS){0,-1,0,1,'L'},R=(POS){0,1,0,-1,'R'};
    U=(POS){-1,0,-1,0,'U'},D=(POS){1,0,1,0,'D'};
    St=(POS){20,20,20,1,0},End=(POS){1,20,1,1,0};
}
POS Walk(POS Now,POS Dir)
{   POS New=Now+Dir;
    if(M1[New.X1][New.Y1]=='#') New.X1=Now.X1,New.Y1=Now.Y1;
    if(M2[New.X2][New.Y2]=='#') New.X2=Now.X2,New.Y2=Now.Y2;
    New.K=0;
    POS &Lp=Last[New.X1][New.Y1][New.X2][New.Y2];
    if(Lp==Zero) Lp=Now,Lp.K=Dir.K,Team.push(New);
    return New;
}
void Bfs()
{   Team.push(St),Last[20][20][20][1]=St;
    for(POS Now;!Team.empty();)
    {   Now=Team.front(),Team.pop();
        if(Walk(Now,D)==End) return ;
        if(Walk(Now,L)==End) return ;
        if(Walk(Now,R)==End) return ;
        if(Walk(Now,U)==End) return ;
    }
}
void Print()
{   POS Now=End;
    while(!(Now==St))
        M1[Now.X1][Now.Y1]=M2[Now.X2][Now.Y2]='A',Now=Last[Now.X1][Now.Y1][Now.X2][Now.Y2],Ans[++As]=Now.K;
    printf("%d\n",--As);
    for(int i=As;i>=1;i--) putchar(Ans[i]);
    puts(""),M1[St.X1][St.Y1]=M2[St.X2][St.Y2]='A';
    for(int i=1;i<=20;i++)
    {   for(int j=1;j<=20;j++) putchar(M1[i][j]);
        putchar(' ');
        for(int j=1;j<=20;j++) putchar(M2[i][j]);
        puts("");
    }
}
int main()
{   Prepare();
    for(int i=1;i<=20;i++) cin>>M1[i]+1>>M2[i]+1;
    for(int i=0;i<=21;i++) M1[i][0]=M1[i][21]=M1[0][i]=M1[21][i]=M2[i][0]=M2[i][21]=M2[0][i]=M2[21][i]='#';
    Bfs(),Print();
}
G

 

K:Stack

题意:

已知若干时刻单调栈的大小,构造一个合法的原序列。\( n \leq 10^6 \) 。

分析:

这题比赛时我曾想用差分、前缀和之类的东西。反正G写了链表然后过了。

看了看,写得真棒。然后我模仿了。

#include<iostream>
#include<cstring>
using namespace std;
int const N=1e6+5;
int n,m,a[N],b[N],top,stk[N],pre[N],aft[N];
int main()
{
    scanf("%d%d",&n,&m); memset(b,255,sizeof b);
    for(int i=1,p,x;i<=m;i++)
        scanf("%d%d",&p,&x),b[p]=x;
    if(b[1]!=-1&&b[1]!=1){printf("-1\n"); return 0;}
    stk[++top]=1; aft[0]=1; pre[1]=0; aft[1]=n+1; pre[n+1]=1;//此处角标和值都是位置
    for(int i=2;i<=n;i++)//i是位置
    {
        if(b[i]==-1)
        {
            pre[i]=stk[top]; aft[i]=aft[stk[top]]; aft[stk[top]]=i; pre[aft[i]]=i;
            stk[++top]=i;
        }
        else
        {
            if(top<b[i]-1){printf("-1\n"); return 0;}
            int t=stk[b[i]-1];
            aft[i]=aft[t]; pre[i]=t; pre[aft[t]]=i; aft[t]=i;
            top=b[i]-1; stk[++top]=i;
        }
    }
    int nw=aft[0];
    for(int i=1;i<=n;i++)//i是值
        a[nw]=i,nw=aft[nw];
    for(int i=1;i<=n;i++)printf("%d ",a[i]); printf("\n");
    return 0;
}
me

 

 

L:Wechat Walk

题意:

\( n \) 个人,\( m \) 条无向边表示他们的好友关系,总时间 \( q \) ;每个时刻只有一个人走了若干步;如果一个人某一时刻在其所有直接好友中步数最多,则其这一时刻是冠军;问每个人是冠军的总时长。\( n , m , q \leq 2*10^5 \)。

分析:

一开始以为朋友的朋友也是朋友,后来发现不是,呵呵。

可以分类处理,把朋友个数 \( > \sqrt{n} \) 的人和朋友个数 \( \leq \sqrt{n} \) 的人分开处理,分别称作“大点”和“小点”;一个是人数少,一个是朋友少,就好办了;

用一个数组记录每个人的总步数;每个点开一个 vector,预处理存自己的大点朋友;每个大点自己开一个小根堆,里面是自己的所有朋友,按步数排序;再用一个数组记录每个人进入冠军状态的时刻;

如果当前步数增加的是小点,直接遍历它的朋友,修改冠军,然后(再次)把自己放进大点朋友的堆里;

如果当前步数增加的是大点,从堆里提取朋友,修改它们的冠军(这里要判断一下提取出的信息是否过期了),再修改自己的冠军状态,然后(再次)把自己放进大点朋友的堆里;

最后输出答案。

代码如下:

#include<iostream>
#include<vector>
#include<queue>
#include<cmath>
#define pb push_back
using namespace std;
int const N=2e5+5;
int n,m,tim,id[N],cnt,ans[N],du[N],sum[N],lst[N];
vector<int>to[N],to2[N];
struct Nd{
    int id,s;
    bool operator < (const Nd a) const{
        return s>a.s;
    }
};
priority_queue<Nd>q[N];
int main()
{
    scanf("%d%d%d",&n,&m,&tim);
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        to[x].pb(y); to[y].pb(x);
        du[x]++; du[y]++;
    }
    for(int i=1;i<=n;i++)
        if(du[i]>sqrt(n))id[i]=++cnt;
    for(int i=1;i<=n;i++)
        for(int j=0,v,sz=to[i].size();j<sz;j++)
            if(id[v=to[i][j]]) to2[i].pb(v);
    for(int t=1,u,s;t<=tim;t++)
    {
        scanf("%d%d",&u,&s); sum[u]+=s;
        if(!id[u])
        {
            bool fl=1;
            for(int i=0,v,sz=to[u].size();i<sz;i++)
            {
                if(sum[v=to[u][i]]>=sum[u])
                {
                    fl=0;
                    if(lst[u])ans[u]+=t-lst[u],lst[u]=0;
                }
                if(sum[u]>=sum[v]&&lst[v])ans[v]+=t-lst[v],lst[v]=0;
            }
            if(fl&&!lst[u])lst[u]=t;
            for(int i=0,v,sz=to2[u].size();i<sz;i++)
                if(sum[u]>=sum[v=to2[u][i]])q[v].push((Nd){u,sum[u]});
        }
        else
        {
            bool fl=1;
            while(q[u].size())
            {
                int v=q[u].top().id,ss=q[u].top().s;
                if(ss<sum[v]){q[u].pop(); continue;}
                if(ss>=sum[u])
                {
                    fl=0;
                    if(lst[u])ans[u]+=t-lst[u],lst[u]=0;
                }
                if(ss>sum[u])break;
                if(ss<=sum[u])
                {
                    q[u].pop();
                    if(lst[v])ans[v]+=t-lst[v],lst[v]=0;
                }
            }
            if(fl&&!lst[u])lst[u]=t;
            for(int i=0,v,sz=to2[u].size();i<sz;i++)
                if(sum[u]>=sum[v=to2[u][i]])q[v].push((Nd){u,sum[u]});
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(lst[i])ans[i]+=tim-lst[i];
        printf("%d\n",ans[i]);
    }
    return 0;
}
me

 

posted @ 2021-07-21 19:08  Zinn  阅读(105)  评论(0编辑  收藏  举报