zoukankan      html  css  js  c++  java
  • [洛谷P5163][题解]WD 与地图

    暑假 wzy 鸽鸽讲的自己出的题现在才抽时间补,大惭愧。

    首先如果这个题是无向图那么就秒了,可惜不是。那么区别在哪里?我们发现一条有向边加入后连接的两个点可能会在更晚的一个时间点才强连通,不能直接并查集合并。
    不过很容易发现这个东西是具有二分性的,于是我们秒掉了单个询问。
    那多个询问怎么办呢?我们不能每次都 \(O(n\log n)\) 二分一遍,所以考虑整体二分。
    具体来说,对于当前二分区间和询问区间,我们把中点以前的点加进去跑一遍 Tarjan,用可撤销并查集维护强连通关系。对于已经强连通的点进入左区间,否则还不强连通,进入右区间。
    具体实现比较考验技巧和耐心,可以参考混乱的代码:
    注意空间不要太大也不要太小,考虑好每个数组的用途再开空间。我因为懒看一直 RE 就直接往大里开了,不要学习这种行为

    const int N=400010;
    int n,m,Q,a[N],t[N<<2],cnt;map<pii,int> qwq;
    struct Edge {
      int to,nxt;
    }e[N<<1];
    int hd[N],cn;
    il void ade(int u,int v){
      e[++cn].to=v,e[cn].nxt=hd[u],hd[u]=cn;
    }
    struct Query {
      int opt,u,v,tm;
      bool operator < (const Query &rhs)const{
        return tm==rhs.tm?opt<rhs.opt:tm<rhs.tm;
      }
    }q[N<<1],p[N<<1];
    int f[N],siz[N];stack<pii > stk;
    int F(int k){
      return f[k]==k?k:F(f[k]);
    }
    void Unify(int u,int v){
      u=F(u),v=F(v);if(u==v)return;
      if(siz[u]<siz[v])swap(u,v);
      f[v]=u,siz[u]+=siz[v],stk.push(mkp(u,v));
    }
    il void Delete(int lmt){
      while(stk.size()>lmt){
        pii u=stk.top();stk.pop();
        f[u.y]=u.y,siz[u.x]-=siz[u.y];
      }
    }
    int dfn[N],low[N],tim;bool vis[N];stack<int> st;
    void Tarjan(int u){
      dfn[u]=low[u]=++tim,vis[u]=1,st.push(u);
      for(int i=hd[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(!dfn[v])Tarjan(v),low[u]=min(low[u],low[v]);
        else if(vis[v])low[u]=min(low[u],dfn[v]);
      }
      if(dfn[u]==low[u]){
        while(st.top()!=u){
          int v=st.top();st.pop(),vis[v]=0,Unify(u,v);
        }
        vis[st.top()]=0,st.pop();
      }
    }
    Query ql[N<<1],qr[N<<1];
    void Solve(int l,int r,int L,int R){
      if(L>R)return;
      if(l==r){
        for(int i=L;i<=R;i++)q[i].tm=l;
        return;
      }
      vector<int> nd;int qlt=0,qrt=0,lst=stk.size();
      for(int i=L;i<=R;i++){
        if(q[i].tm>nmid)continue;
        int u=F(q[i].u),v=F(q[i].v);
        nd.pub(u),nd.pub(v),ade(u,v);
      }
      for(int i:nd)if(!dfn[i])Tarjan(i);
      for(int i=L;i<=R;i++){
        if(q[i].tm<=nmid&&F(q[i].u)==F(q[i].v))ql[++qlt]=q[i];
        else qr[++qrt]=q[i];
      }
      for(int i=1;i<=qlt;i++)q[L+i-1]=ql[i];
      for(int i=1;i<=qrt;i++)q[L+i+qlt-1]=qr[i];
      cn=tim=0;
      for(int i:nd)hd[i]=dfn[i]=low[i]=0;
      Solve(nmid+1,r,L+qlt,R),Delete(lst);
      Solve(l,nmid,L,L+qlt-1);
    }
    struct Node {
      int l,r,cnt,w;
    }tr[N*20];
    int rt[N],tot;
    il void Pushup(int k){
      tr[k].cnt=tr[ls].cnt+tr[rs].cnt;
      tr[k].w=tr[ls].w+tr[rs].w;
    }
    void Modify(int &k,int pos,int v,int l,int r){
      if(!k)k=++tot;
      tr[k].cnt+=v,tr[k].w+=v*t[pos];
      if(l==r)return;
      if(pos<=nmid)Modify(ls,pos,v,l,nmid);
      else Modify(rs,pos,v,nmid+1,r);
    }
    LL Query(int k,int v,int l,int r){
      if(tr[k].cnt<=v)return tr[k].w;
      if(l==r)return t[l]*v;
      if(v<=tr[rs].cnt)return Query(rs,v,nmid+1,r);
      else return tr[rs].w+Query(ls,v-tr[rs].cnt,l,nmid);
    }
    int Merge(int u,int v,int l,int r){
      if(!u||!v)return u+v;
      if(l==r){
        tr[u].cnt+=tr[v].cnt,tr[u].w+=tr[v].w;return u;
      }
      tr[u].l=Merge(tr[u].l,tr[v].l,l,nmid);
      tr[u].r=Merge(tr[u].r,tr[v].r,nmid+1,r);
      return Pushup(u),u;
    }
    int ans[N];
    signed main(){
      Read(n),Read(m),Read(Q);
      for(int i=1;i<=n;i++)f[i]=i,siz[i]=1;
      for(int i=1;i<=n;i++)Read(a[i]),t[++cnt]=a[i];
      for(int i=1;i<=m;i++){
        Read(q[i].u),Read(q[i].v),qwq[mkp(q[i].u,q[i].v)]=i;
      }
      for(int i=1,u,v;i<=Q;i++){
        Read(p[i].opt),Read(u),Read(v),p[i].tm=Q-i+1;
        p[i].u=u,p[i].v=v;
        if(p[i].opt==1)q[qwq[mkp(u,v)]].tm=p[i].tm;
        else if(p[i].opt==2)a[u]+=v,cnt++,a[cnt]=t[cnt]=a[u];
      }
      sort(t+1,t+1+cnt);int tmp=unique(t+1,t+1+cnt)-t-1;
      Solve(0,Q+1,1,m);
      for(int i=1;i<=n;i++)f[i]=i,siz[i]=1;
      for(int i=1;i<=n;i++){
        int qwq=lower_bound(t+1,t+1+tmp,a[i])-t;
        Modify(rt[i],qwq,1,1,tmp);
      }
      for(int i=1;i<=Q;i++)if(p[i].opt!=1)q[++m]=p[i];
      sort(q+1,q+m+1);
      for(int i=1;i<=m;i++){
        int u=q[i].u,v=q[i].v;
        if(q[i].opt==0){
          u=F(u),v=F(v);
          if(u==v)continue;
          if(siz[u]<siz[v])swap(u,v);
          siz[u]+=siz[v],f[v]=u;
          rt[u]=Merge(rt[u],rt[v],1,tmp);
        }else if(q[i].opt==2){
          int fa=F(u);
          int qwq=lower_bound(t+1,t+1+tmp,a[u])-t;
          a[u]-=v;
          int awa=lower_bound(t+1,t+1+tmp,a[u])-t;
          Modify(rt[fa],qwq,-1,1,tmp);
          Modify(rt[fa],awa,1,1,tmp);
        }else {
          int fa=F(u);
          ans[Q-q[i].tm+1]=Query(rt[fa],v,1,tmp);
        }
      }
      for(int i=1;i<=Q;i++){
        if(p[i].opt==3)printf("%lld\n",ans[i]);
      }
      KafuuChino HotoKokoa
    }
    
    内容来自_ajthreac_的博客(https://www.cnblogs.com/juruoajh/),未经允许,不得转载。
  • 相关阅读:
    sqlite3获取所有表信息
    top高级技能
    python xlwt写excel格式控制 颜色、模式、编码、背景色
    python操作Excel的几种方式
    eclispe: 修改所有文件默认编码为UTF-8
    Fragment: 使用newInstance()来实例化fragment(转)
    Java: 线程池(ThreadPoolExecutor)中的参数说明
    android : 解决android无法使用sun.misc.BASE64Encoder sun.misc.BASE64Decoder 的问题, 无需添加rt.jar
    蓝牙BLE: ATT协议层中属性(Attribute)
    蓝牙BLE: ATT和GATT的概念
  • 原文地址:https://www.cnblogs.com/juruoajh/p/15668965.html
Copyright © 2011-2022 走看看