P3733 [HAOI2017] 八纵八横

题意

一张 \(n\) 个点,\(m\) 条边的无向带权联通图,定义一条路径长度为路径上所有边的边权异或和。几种操作:加边,删边,修改边权。每次操作完后问图上从 \(1\) 出发,在 \(1\) 结束的最长路径的长度,操作总共 \(q\) 次。每条边的边权是长度为 \(len\) 的二进制数
\(n,m\le500\ len,q\le1000\)

思路

显然可以线段树分治,但我不想写。使用可撤销线性基。

可撤销线性基 在线性基的每一位上记录那个元素最晚被删除的元素,插入时带上被删除的时间。显然,把晚删除的放高位更优,所以当碰到某一位删除时间比新插入的元素早时,交换祂们。查询时也带上时间,判断一下每个元素现在有没有被删除。

对于本题,对原图跑一颗生成树,那么这棵树的形态是不会变的,那么加边只有一定会形成环。把操作离线,统计出每条边的出现时间和删除时间,按时间顺序加边并统计答案。可以把修改边权看作删一条边在加一条边(标号不变)

代码

// Problem: P3733 [HAOI2017] 八纵八横
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3733
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
const int maxn=510,maxlen=1010,maxq=1010,inf=1000000000;
#define B bitset<maxlen>
namespace IO{
    template<typename T>
    inline void read(T&x){
        x=0;char c=getchar();bool f=0;
        while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
        while(isdigit(c)) x=x*10+c-'0',c=getchar();
        f?x=-x:0;
    }
    template<typename T>
    inline void write(T x){
        if(x==0){putchar('0');return ;}
        x<0?x=-x,putchar('-'):0;short st[50],top=0;
        while(x) st[++top]=x%10,x/=10;
        while(top) putchar(st[top--]+'0');
    }
    inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
    inline void write(char c){putchar(c);}
    inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
    inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
    inline void read(B&x){
        string s;read(s);
        reverse(s.begin(),s.end());
        for(int i=0;i<s.size();i++) if(s[i]=='1') x.set(i);else x.reset(i);
    }
    template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
    template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
    template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
int n,m,q,fa[maxn],cnt_edge,be[maxq];
vector<pair<int,B>>e[maxn],qu[maxq];
B dis[maxn];
bool vis[maxn],era[maxn];
struct edge{int u,v;B w;}b[maxq];
inline void write(B t){
    int be=1000;
    while(be&&!t.test(be)) be--;
    for(;be>=0;be--) if(t.test(be)) write(1);else write(0);
    write("\n");
}
class XXJ{
private:
    B d[maxlen];
    int t_del[maxlen];
public:
    void insert(B a,int ti){
        for(int i=1000;i>=0;i--){
            if(!a.test(i)) continue;
            if(ti>t_del[i]) swap(ti,t_del[i]),swap(a,d[i]);
            if(ti==0) break;
            a^=d[i];
        }
    }
    B query(int ti){
        B ans;ans.reset();
        for(int i=1000;i>=0;i--){
            if(ans.test(i)) continue;
            if(ti<t_del[i]) ans^=d[i];
        }
        return ans;
    }
}xj;
void dfs(int u,int fa=0){
    ::fa[u]=fa;
    vis[u]=1;
    for(auto[v,w]:e[u]){
        if(v==fa) continue;
        if(vis[v]){
            xj.insert(dis[u]^dis[v]^w,inf);
            continue;
        }
        dis[v]=dis[u]^w;
        dfs(v,u);
    }
}
signed main(){
    read(n,m,q);
    for(int i=1;i<=m;i++){
        int u,v;B w;read(u,v,w);
        e[u].push_back({v,w}),e[v].push_back({u,w});
    }
    dfs(1);
    for(int i=1;i<=q;i++){
        string op;read(op);
        if(op=="Add"){
            cnt_edge++;
            read(b[cnt_edge].u,b[cnt_edge].v,b[cnt_edge].w);
            be[cnt_edge]=i;
        }
        if(op=="Cancel"){
            int k;read(k);
            qu[be[k]].push_back({i,b[k].w^dis[b[k].u]^dis[b[k].v]});
            era[k]=1;
        }
        if(op=="Change"){
            int k;B z;
            read(k,z);
            qu[be[k]].push_back({i,b[k].w^dis[b[k].u]^dis[b[k].v]});
            be[k]=i,b[k].w=z;
        }
    }
    for(int i=1;i<=cnt_edge;i++){
        if(era[i]) continue;
        qu[be[i]].push_back({inf,b[i].w^dis[b[i].u]^dis[b[i].v]});
    }
    write(xj.query(0));
    for(int i=1;i<=q;i++){
        for(auto[ti,x]:qu[i]) xj.insert(x,ti);
        write(xj.query(i));
    }
    return 0;
}
posted @ 2026-04-27 21:09  Link-Cut_Trees  阅读(12)  评论(0)    收藏  举报