zoukankan      html  css  js  c++  java
  • WD与地图 解题报告

    WD与地图

    哎,我好傻啊,看了题解还弄错了一遍,靠着lbw指点才董


    题意:给一个带点权有向图,要求支持删边,查询一个scc前(k)大权值,修改点权,强制在线。


    显然倒序处理变成加边

    考虑求出每条边两点在一个scc里面的最小时间

    这样可以按时间对每个scc维护一个线段树,跑权值线段树合并

    可以对每个边二分答案,然后想到整体二分

    假设现在二分的时间为([l,r]),划分到这个区间的边为([s,t])

    那么小于(l)的边形成的图一定已经是一个scc了,我们用并查集维护一个类似虚图的东西维护每个已经好了的scc

    然后把时间在([l,mid])的边加入scc虚图跑tarjan,最后划分一下边([s,t])进入左边还是右边

    注意到维护scc的并查集需要可撤回


    Code:

    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #include <map>
    #define ll long long
    const int N=4e5+10;
    using std::min;
    template <class T>
    void read(T &x)
    {
        x=0;char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) x=x*10+c-'0',c=getchar();
    }
    std::map <int,int> ma[N];
    struct node
    {
        int u,v,tim,ad;
        bool friend operator <(node a,node b){return a.tim<b.tim;}
    }E[N],El[N],Er[N];
    struct Query
    {
        int op,a,b;
    }Q[N];
    int head[N],to[N<<1],Next[N<<1],cnt;
    void add(int u,int v)
    {
        to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
    }
    int n,m,q,k,_m;
    int root[N],ch[N*60][2],siz[N*60],ct;
    ll sum[N*60],ss[N],yuy[N],ans[N];
    #define ls ch[now][0]
    #define rs ch[now][1]
    void upt(int &now,int l,int r,int p,int d)
    {
        if(!now) now=++ct;
        if(l==r)
        {
            siz[now]+=d;
            sum[now]=1ll*siz[now]*yuy[l];
            return;
        }
        int mid=l+r>>1;
        if(p<=mid) upt(ls,l,mid,p,d);
        else upt(rs,mid+1,r,p,d);
        siz[now]=siz[ls]+siz[rs];
        sum[now]=sum[ls]+sum[rs];
    }
    int Merge(int x,int y,int l,int r)
    {
        if(!x||!y) return x^y;
        if(l==r)
        {
            sum[x]+=sum[y];
            siz[x]+=siz[y];
            return x;
        }
        int mid=l+r>>1;
        ch[x][0]=Merge(ch[x][0],ch[y][0],l,mid);
        ch[x][1]=Merge(ch[x][1],ch[y][1],mid+1,r);
        siz[x]=siz[ch[x][0]]+siz[ch[x][1]];
        sum[x]=sum[ch[x][0]]+sum[ch[x][1]];
        return x;
    }
    ll query(int now,int l,int r,int p)
    {
        if(l==r) return 1ll*p*yuy[l];
        int mid=l+r>>1;
        if(siz[rs]>=p) return query(rs,mid+1,r,p);
        else return query(ls,l,mid,p-siz[rs])+sum[rs];
    }
    int f[N],hei[N],eu[N],ev[N],Tim;
    void del(int id)
    {
        f[ev[id]]=ev[id];
        if(eu[id]) --hei[eu[id]];
    }
    int Find(int x){return f[x]==x?x:Find(f[x]);}
    void Merge2(int u,int v)
    {
        u=Find(u),v=Find(v);
        if(u==v) return;
        if(hei[u]<hei[v]) std::swap(u,v);
        f[v]=u;
        root[u]=Merge(root[u],root[v],1,k);
        if(hei[u]==hei[v]) ++hei[u];
    }
    void Merge(int u,int v)
    {
        u=Find(u),v=Find(v);
        if(u==v) return;
        if(hei[u]<hei[v]) std::swap(u,v);
        ++Tim;
        eu[Tim]=0,ev[Tim]=v;
        f[v]=u;
        if(hei[u]==hei[v])
        {
            ++hei[u];
            eu[Tim]=u;
        }
    }
    int dfn[N],low[N],s[N],tot,in[N],dfsclock;
    void tarjan(int now)
    {
        dfn[now]=low[now]=++dfsclock;
        s[++tot]=now;
        in[now]=1;
        for(int v,i=head[now];i;i=Next[i])
        {
            v=to[i];
            if(!dfn[v])
            {
                tarjan(v);
                low[now]=min(low[now],low[v]);
            }
            else if(in[v])
                low[now]=min(low[now],dfn[v]);
        }
        if(dfn[now]==low[now])
        {
            int k=s[tot--],las;
            in[k]=0;
            while(k!=now)
            {
                las=k,k=s[tot--];
                in[k]=0;
                Merge(las,k);
            }
        }
    }
    int pot[N];
    void solve(int s,int t,int l,int r)
    {
        if(s>t) return;
        int mid=l+r>>1;
        int tim=Tim;
        for(int i=s;i<=t;i++)
            if(E[i].ad<=mid)
            {
                int u=Find(E[i].u),v=Find(E[i].v);
                pot[++pot[0]]=u,pot[++pot[0]]=v;
                add(u,v);
            }
        std::sort(pot+1,pot+pot[0]+1);
        pot[0]=std::unique(pot+1,pot+pot[0]+1)-pot-1;
        for(int i=1;i<=pot[0];i++)
        {
            int now=pot[i];
            if(!dfn[now])
                tarjan(now);
        }
        int lp=0,rp=0;
        for(int i=s;i<=t;i++)
        {
            int u=E[i].u,v=E[i].v;
            if(Find(u)==Find(v)) E[i].tim=mid,El[++lp]=E[i];
            else Er[++rp]=E[i];
        }
        for(int i=1;i<=lp;i++) E[s+i-1]=El[i];
        for(int i=1;i<=rp;i++) E[s+lp+i-1]=Er[i];
    
        for(int i=1;i<=pot[0];i++) head[pot[i]]=dfn[pot[i]]=low[pot[i]]=0;
        pot[0]=cnt=dfsclock=0;
    
        if(l!=r) solve(s+lp,t,mid+1,r);
        while(Tim>tim) del(Tim--);
        if(l!=r) solve(s,s+lp-1,l,mid);
    }
    int main()
    {
        read(n),read(m),read(q);k=n;
        for(int i=1;i<=n;i++) read(ss[i]),yuy[i]=ss[i];
        for(int i=1;i<=m;i++) read(E[i].u),read(E[i].v),E[i].tim=q+1,ma[E[i].u][E[i].v]=i;
        for(int i=1;i<=q;i++)
        {
            read(Q[i].op),read(Q[i].a),read(Q[i].b);
            if(Q[i].op==1) E[ma[Q[i].a][Q[i].b]].ad=q+1-i;
            if(Q[i].op==2) ss[Q[i].a]+=Q[i].b,yuy[++k]=ss[Q[i].a];
        }
        std::sort(yuy+1,yuy+1+k);
        k=std::unique(yuy+1,yuy+1+k)-yuy-1;
        std::reverse(Q+1,Q+1+q);
        for(int i=1;i<=n;i++) f[i]=i,hei[i]=1;
        solve(1,m,0,q);
        std::sort(E+1,E+1+m);
        for(int i=1;i<=n;i++)
        {
            int p=std::lower_bound(yuy+1,yuy+1+k,ss[i])-yuy;
            upt(root[i],1,k,p,1);
        }
        for(int j=1,i=1;i<=q;i++)
        {
            while(j<=m&&E[j].tim<=i)
            {
                Merge2(E[j].u,E[j].v);
                ++j;
            }
            if(Q[i].op==2)
            {
                int u=Q[i].a,dec=Q[i].b,rtu=Find(u);
                int p=std::lower_bound(yuy+1,yuy+1+k,ss[u])-yuy;
                upt(root[rtu],1,k,p,-1);
                ss[u]-=dec;
                p=std::lower_bound(yuy+1,yuy+1+k,ss[u])-yuy;
                upt(root[rtu],1,k,p,1);
            }
            if(Q[i].op==3)
            {
                int u=Find(Q[i].a),t=Q[i].b;
                if(siz[root[u]]<t) ans[++ans[0]]=sum[root[u]];
                else ans[++ans[0]]=query(root[u],1,k,t);
            }
        }
        for(int i=ans[0];i;i--) printf("%lld
    ",ans[i]);
        return 0;
    }
    

    2019.4.15

  • 相关阅读:
    back-不忘初心,方得始终。讲讲我主场3个月的经历。题外话。
    js中event事件对象的兼容问题以及坐标属性-(clientX clientY;pageX,pageY,offsetX,offsetY)
    布局(左边的div随着右边div的高度变化而变化)
    事件委托如何实现的原理
    寄生组合式继承方法的实现以及原理总结
    封装判断一个字符的后缀名和前缀的方法
    经典的面试题如果不通过其他任何变量实现两个数值类型的变量互相更换值。
    【十次方基础教程(后台)】Dockerfile脚本完成镜像的构建
    【十次方基础教程(后台)】安装并启动RabbitMQ
    【十次方基础教程(后台)】docker下安装head插件来进行Elasticsearch的操作
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10713545.html
Copyright © 2011-2022 走看看