Educational Codeforces Round 38 G:Shortest Path Queries(线段树+并查集)

传送门

题解:
xy x → y 的所有路径都可以由 xy x → y dfs d f s 树上的路径抑或图中的环得到。

然后问题变为了动态维护 dfs d f s 树和所有环(支持删边加边),这个显然是不大可做的,不过如果只有加边操作就很简单了。

然后发现可以离线,就可以把一条边的出现区间放到 logn log ⁡ n 个线段树的节点上,然后从上往下 dfs d f s 线段树处理所有询问即可。

注意要支持撤销,所以加边用按秩合并的并查集。

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
inline int rd() {
    char ch=getchar(); int i=0,f=1;
    while(!isdigit(ch)) {if(ch=='-')f=-1; ch=getchar();}
    while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=getchar();}
    return i*f;
}
const int N=2e5+50,LIM=30;
map < pii,int > mp;
map < pii,int > mp_v;
int n,m;
int rk[N],val[N],anc[N];
int base[LIM+5],pos[LIM+5],top;
struct data {
    int u,x,y,w,c;
    data(int u,int x,int y,int w,int c):u(u),x(x),y(y),w(w),c(c){}
    friend inline bool operator <(const data &a,const data &b) {return a.u<b.u;}
};
vector <data> qry[N*4];
inline void insert(int k,int l,int r,int L,int R,const data &t) {
    if(L<=l&&r<=R) {qry[k].push_back(t); return;}
    int mid=(l+r)>>1;
    if(R<=mid) insert(k<<1,l,mid,L,R,t);
    else if(L>mid) insert(k<<1|1,mid+1,r,L,R,t);
    else insert(k<<1,l,mid,L,R,t),insert(k<<1|1,mid+1,r,L,R,t);
}
inline pii getanc(int x) {
    int rs=0;
    while(x!=anc[x]) rs^=val[x],x=anc[x];
    return make_pair(x,rs);
}
inline int inc(int x) {
    for(int i=LIM;~i;i--) if(pos[i] && (x&(1<<i))) x^=base[pos[i]];
    for(int i=LIM;~i;i--) if(!pos[i] && (x&(1<<i))) {
        base[++top]=x; pos[i]=top;
        return i;
    } return -1;
}
inline int query(int x,int y) {
    x=getanc(x).second^getanc(y).second;
    for(int i=LIM;~i;i--) if(pos[i] && (x&(1<<i))) x=x^base[pos[i]];
    return x;
}
inline void dfs(int k,int l,int r) {
    if(l==r) sort(qry[k].begin(),qry[k].end());
    for(int i=0;i<qry[k].size();++i) {
        data t=qry[k][i];
        if(t.u==1) {
            pii x=getanc(t.x),y=getanc(t.y);
            if(x.first==y.first) {
                int p=inc(x.second^y.second^t.w);
                if(~p) qry[k][i].c=3+p;
            } else {
                if(rk[x.first]<rk[y.first]) swap(x,y);
                anc[y.first]=x.first; val[y.first]=t.w^x.second^y.second;
                if(rk[x.first]==rk[y.first]) ++rk[x.first],qry[k][i].c=2;
                else qry[k][i].c=1;
                qry[k][i].x=x.first,qry[k][i].y=y.first;
            }
        } else printf("%d\n",query(t.x,t.y));
    } 
    if(l!=r) {
        int mid=(l+r)>>1;
        dfs(k<<1,l,mid); 
        dfs(k<<1|1,mid+1,r);
    }
    for(int i=qry[k].size()-1;i>=0;i--) {
        data t=qry[k][i];
        if(!t.c) continue;
        if(t.c<=2) {
            anc[t.y]=t.y; val[t.y]=0;
            rk[t.x]-=(t.c-1);
        } else {
            pos[t.c-3]=0; 
            --top;
        }
    }
}
int main() {
    n=rd(), m=rd();
    for(int i=1;i<=n;i++) anc[i]=i;
    for(int i=1;i<=m;i++) {
        int x=rd(), y=rd(), w=rd();
        if(x>y) swap(x,y);
        mp[make_pair(x,y)]=0;
        mp_v[make_pair(x,y)]=w;
    }
    m=rd();
    for(int i=1;i<=m;i++) {
        int op=rd(), x=rd(), y=rd();
        if(x>y) swap(x,y);
        if(op==1) {
            int w=rd();
            mp[make_pair(x,y)]=i;
            mp_v[make_pair(x,y)]=w;
        } else if(op==2) {
            int pre=mp[make_pair(x,y)],w=mp_v[make_pair(x,y)];
            mp.erase(mp.find(make_pair(x,y)));
            mp_v.erase(mp_v.find(make_pair(x,y)));
            insert(1,0,m,pre,i,data(1,x,y,w,0));
        } else insert(1,0,m,i,i,data(2,x,y,0,0));
    }
    for(map< pair<int,int>,int >::iterator it=mp.begin(),it2=mp_v.begin();it!=mp.end();++it,++it2) 
        insert(1,0,m,it->second,m,data(1,it->first.first,it->first.second,it2->second,0));
    dfs(1,0,m);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值