洛谷P5163《WD与地图》题解

题目传送门

题目背景

WD整日沉浸在地图中,无法自拔……

题目描述

CX让WD研究的地图可以看做是nn个点,mm条边的有向图,由于政府正在尝试优化人民生活,他们会废弃一些无用的道路来把省下的钱用于经济建设。

城市都有各自的发达程度s_is
i
​ 。为了方便管理,政府将整个地图划分为一些地区,两个点u,vu,v在一个地区当且仅当u,vu,v可以互相到达。政府希望知道一些时刻某个地区的前kk发达城市的发达程度总和,以此推断建设的情况。

也就是说,共有三个操作:

1 a b表示政府废弃了从aa连向bb的边,保证这条边存在。

2 a b表示政府把钱用于建设城市aa,使其发达程度增加b.

3 a b表示政府希望知道aa城市所在地区发达程度前bb大城市的发达程度之和。如果地区中的城市不足bb个输出该地区所有城市的发达程度总和。

AC代码:

#include<bits/stdc++.h>
#define pb push_back
#define mkp make_pair
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=4e5+10,M=N*50;
int tn,n,m,Q,cnt,val[N];
vector<ll>ans;
set<pii>E;
ll res[N];

namespace IO
{
    int read()
    {
        int ret=0;char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
        return ret;
    }
    void write(ll x)
    {
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    void writeln(ll x){write(x);puts("");}
}
using namespace IO;

namespace Segment
{
    int sz,ls[M],rs[M],cnt[M],rt[N];
    ll sum[M];
    void update(int &x,int l,int r,int p,int v)
    {
        if(!x)x=++sz;cnt[x]+=v;sum[x]+=(ll)p*v;
        if(l==r) return;
        int mid=(l+r)>>1;
        if(p<=mid) update(ls[x],l,mid,p,v);
        else update(rs[x],mid+1,r,p,v);
    }
    ll query(int x,int l,int r,int p)
    {
        if(p>=cnt[x]) return sum[x];
        if(l==r) return sum[x]/cnt[x]*p;
        int mid=(l+r)>>1;
        if(cnt[rs[x]]>=p) return query(rs[x],mid+1,r,p);
        else return query(ls[x],l,mid,p-cnt[rs[x]])+sum[rs[x]];
    }
    int Tmerge(int x,int y)
    {
        if(!x || !y) return x+y;
        cnt[x]+=cnt[y];sum[x]+=sum[y];
        ls[x]=Tmerge(ls[x],ls[y]);
        rs[x]=Tmerge(rs[x],rs[y]);
        return x;
    }
}
using Segment::update;
using Segment::query;
using Segment::Tmerge;
using Segment::rt;

namespace DSU
{
    int fa[N];
    int findf(int x){return fa[x]==x?x:fa[x]=findf(fa[x]);}
    void merge(int x,int y)
    {
        x=findf(x);y=findf(y);
        if(x==y) return;
        if(x>y) swap(x,y);
        fa[x]=y;
    }
}
using namespace DSU;

namespace Graph
{
    int ind,tot;
    int low[N],dfn[N],ins[N],head[N];
    stack<int>st;
    struct edge
    {
        int u,v,t;
        edge(int _u=0,int _v=0,int _t=0):u(_u),v(_v),t(_t){}
    }g[N],cpy[N];
    vector<edge>mp[N];
    struct Tway
    {
        int v,nex;
        Tway(int _v=0,int _nex=0):v(_v),nex(_nex){}
    }e[N];
    void addedge(int u,int v){e[++tot]=Tway(v,head[u]);head[u]=tot;}
    void clear(int x){low[x]=dfn[x]=ins[x]=0;}
    void tarjan(int x)
    {
        dfn[x]=low[x]=++ind;ins[x]=1;st.push(x);
        for(int i=head[x];i;i=e[i].nex)
        {
            int v=e[i].v;
            if(!dfn[v]) tarjan(v),low[x]=min(low[x],low[v]);
            else if(ins[v]) low[x]=min(low[x],dfn[v]);
        }
        if(low[x]^dfn[x]) return;
        for(int t=0;t^x;t=st.top(),st.pop()) merge(st.top(),x),ins[st.top()]=0;
    }
}
using Graph::addedge;
using Graph::tarjan;
using Graph::dfn;
using Graph::edge;
using Graph::mp;
using Graph::g;
using Graph::cpy;

namespace Divide_Conquer
{
    pii arr[N];
    void solve(int l,int r,int L,int R)
    {
        //cerr<<l<<" "<<r<<" "<<L<<" "<<R<<endl;
        if(l==r)
        { 
            for(int i=L;i<=R;++i) mp[l].pb(g[i]);
            return;
        }
        if(L==R)
        {
            mp[(findf(g[L].u)==findf(g[L].v))?g[L].t:Q+1].pb(g[L]);
            return;
        }
        int mid=(l+r)>>1,c=0;
        for(int i=L;i<=R;++i) if(g[i].t<=mid)
        {
            int u=findf(g[i].u),v=findf(g[i].v);
            arr[++c]=mkp(u,v);Graph::head[u]=Graph::head[v]=0;
        }
        Graph::tot=0;
        for(int i=1;i<=c;++i)
        {
            int u=arr[i].fi,v=arr[i].se;addedge(u,v);
            Graph::clear(u);Graph::clear(v);
        }
        //cerr<<c<<endl;
        //if(r==12500) exit(0);
        Graph::ind=0;
        while(!Graph::st.empty()) Graph::st.pop();
        for(int i=1;i<=c;++i)
        {
            if(!dfn[arr[i].fi]) tarjan(arr[i].fi);
            if(!dfn[arr[i].se]) tarjan(arr[i].se);
        }
        int tl=0,tr=L,t=1;vector<pii> cp;
        for(int i=L;i<=R;++i)
        {
            int fg=0;
            if(g[i].t<=mid)
            {
                int u=arr[t].fi,v=arr[t].se;++t;
                if(findf(u)==findf(v)) fg=1;
                cp.pb(mkp(u,fa[u]));cp.pb(mkp(v,fa[v]));
            }
            if(fg) g[tr++]=g[i]; else cpy[++tl]=g[i];
        }
        for(int i=tr;i<=R;++i) g[i]=cpy[i-tr+1];
        for(int i=1;i<=c;++i) fa[arr[i].fi]=arr[i].fi,fa[arr[i].se]=arr[i].se;
        if(L<tr) solve(l,mid,L,tr-1);
        for(vector<pii>::iterator it=cp.begin();it!=cp.end();++it) fa[(*it).fi]=(*it).se;
        //exit(0);
        if(tr<=R) solve(mid+1,r,tr,R);
    }
}

struct Tquery
{
    int t,a,b;
    Tquery(int _t=0,int _a=0,int _b=0):t(_t),a(_a),b(_b){}	
}qs[N];

int main()
{
#ifndef ONLINE_JUDGE
    freopen("LGP5163.in","r",stdin);
    freopen("LGP5163.out","w",stdout);
#endif
    n=read();m=read();Q=read();
    for(int i=1;i<=n;++i) val[i]=read(),fa[i]=i;
    for(int i=1,u,v;i<=m;++i) u=read(),v=read(),E.insert(mkp(u,v));
    for(int i=Q;i;--i)
    {
        int t=read(),a=read(),b=read();
        qs[i]=Tquery(t,a,b);
        if(t==1) g[++cnt]=edge(a,b,i),E.erase(mkp(a,b));
        else if(t==2) val[a]+=b;
    }
    for(set<pii>::iterator it=E.begin();it!=E.end();++it) g[++cnt]=edge((*it).fi,(*it).se,0);
    Divide_Conquer::solve(0,Q+1,1,m);
    for(int i=1;i<=n;++i) tn=max(tn,val[fa[i]=i]);
    for(int i=1;i<=n;++i) update(rt[i],1,tn,val[i],1);
    qs[0].t=1;
    for(int i=0;i<=Q;++i)
    {
        if(qs[i].t==1)
        {
            for(vector<edge>::iterator it=mp[i].begin();it!=mp[i].end();++it)
            {
                int u=(*it).u,v=(*it).v;
                u=findf(u);v=findf(v);
                if(u==v) continue;
                fa[v]=u;rt[u]=Tmerge(rt[u],rt[v]);
            }
        }
        else if(qs[i].t==2)
        {
            int x=findf(qs[i].a),&v=val[qs[i].a];
            update(rt[x],1,tn,v,-1);update(rt[x],1,tn,v-=qs[i].b,1);
        }
        else ans.pb(query(rt[findf(qs[i].a)],1,tn,qs[i].b));
    }
    for(int i=(int)ans.size()-1;~i;--i) writeln(ans[i]);//printf("%lld\n",ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yingyouyu/article/details/87895382