HAOI2017 八縱八橫——線段樹分治+線性基
阿新 • • 發佈:2019-04-03
給定 靜態 include 不支持 ins urn ons divide amp
題目大意
給定一個圖,每次加一些邊,或者刪掉一些後來加上去的邊,定義一個環的價值為環上所有的邊的異或和,重復走的邊重復算。每次詢問這個時刻圖中的所有經過1號點的環的最大價值。
思路
首先考慮對於一個靜態的圖如何求解圖中所有經過1號點的環的最大價值,發現這個經過1號點就是唬人的,圖中任意一個環都可以經過1號點再走回來。
於是題目變成了求解圖中環的最大價值,可以將圖中所有的簡單環給拎出來放到線性基裏面求最大價值,不難發現這是對的。
然後題目轉化為了如何求圖中所有的簡單環,一般我們可以直接對圖dfs找環,這個題目可以隨便建出一顆生成樹,任何一條非樹邊都對應了一個簡單環,於是我們每次只需要在樹上加邊刪邊即可。
但是線性基不支持刪除啊,線段樹分治就好了。
/*======================================= * Author : ylsoi * Time : 2019.4.3 * Problem : luogu3733 * E-mail : [email protected] * ====================================*/ #include<bits/stdc++.h> #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i) #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i) #define debug(x) cout<<#x<<"="<<x<<" " #define fi first #define se second #define mk make_pair #define pb push_back #define pii pair<bitset<maxn>,int> typedef long long ll; using namespace std; void File(){ freopen("luogu3733.in","r",stdin); freopen("luogu3733.out","w",stdout); } template<typename T>void read(T &_){ _=0; T f=1; char c=getchar(); for(;!isdigit(c);c=getchar())if(c=='-')f=-1; for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0'); _*=f; } string proc(){ ifstream f("/proc/self/status"); return string(istreambuf_iterator<char>(f),istreambuf_iterator<char>()); } const int maxn=1000+10; int n,m,q,tot; struct edge{ int u,v,l,r; bitset<maxn>w; }e[maxn]; vector<pii>G[maxn]; vector<edge>lis; bitset<maxn>dis[maxn]; void read_bitset(bitset<maxn>&x){ static char strbuf[maxn]; char ch=getchar(); int tp=0; for(;!isdigit(ch);ch=getchar()); for(;isdigit(ch);ch=getchar())strbuf[tp++]=ch; tot=max(tot,tp),x.reset(); DREP(i,tp-1,0)if(strbuf[tp-1-i]=='1')x.set(i); } void output(bitset<maxn>&x,char ch='\n'){ int p=0; DREP(i,tot-1,0)if(x[i]){p=i;break;} DREP(i,p,0)putchar(x[i]+48); putchar(ch); } int fa[maxn]; int find(int x){return fa[x]==x ? x : fa[x]=find(fa[x]);} void dfs_init(int u,int fh){ REP(i,0,G[u].size()-1){ bitset<maxn>w=G[u][i].fi; int v=G[u][i].se; if(v==fh)continue; /*cout<<u<<" "<<v<<endl; output(w);*/ dis[v]=dis[u]^w; dfs_init(v,u); } } struct liner_base{ bitset<maxn>b[maxn]; liner_base(){DREP(i,tot-1,0)b[i].reset();} void insert(bitset<maxn>x){ DREP(i,tot-1,0)if(x[i]){ if(!b[i][i]){b[i]=x;break;} x^=b[i]; } } bitset<maxn>query(){ bitset<maxn>ret(0); DREP(i,tot-1,0)if(!ret[i] && b[i][i]) ret^=b[i]; return ret; } }T[21]; void init(){ read(n),read(m),read(q); REP(i,1,n)fa[i]=i; int u,v; REP(i,1,m){ read(u),read(v),read_bitset(e[i].w); e[i].u=u,e[i].v=v; //output(e[i].w); if(find(u)!=find(v)){ fa[find(u)]=find(v); G[u].push_back(mk(e[i].w,v)); G[v].push_back(mk(e[i].w,u)); } else lis.push_back(e[i]); } dfs_init(n,0); } #define mid ((l+r)>>1) #define lc (o<<1) #define rc (o<<1|1) #define lson lc,l,mid #define rson rc,mid+1,r vector<bitset<maxn> >t[maxn<<2]; void insert(int o,int l,int r,int L,int R,bitset<maxn>&x){ if(L<=l && r<=R)t[o].push_back(x); else{ if(L<=mid)insert(lson,L,R,x); if(R>=mid+1)insert(rson,L,R,x); } } void divide(int o,int l,int r,int dep){ REP(i,0,t[o].size()-1) T[dep].insert(t[o][i]); if(l==r){ bitset<maxn>ans=T[dep].query(); output(ans); } else{ T[dep+1]=T[dep]; divide(lson,dep+1); T[dep+1]=T[dep]; divide(rson,dep+1); } } vector<edge>tl[maxn]; void work(){ char opt[11]; int u,v,cnt=0; bitset<maxn>w; REP(i,0,lis.size()-1){ w=dis[lis[i].u]^dis[lis[i].v]^lis[i].w; insert(1,1,q+1,1,q+1,w); } REP(i,1,q){ scanf("%s",opt); if(opt[0]=='A'){ read(u),read(v),read_bitset(w); tl[++cnt].push_back((edge){u,v,i+1,q+1,w}); } else if(opt[1]=='h'){ read(u),read_bitset(w); int las=tl[u].size()-1; tl[u][las].r=i; tl[u].push_back((edge){tl[u][las].u,tl[u][las].v,i+1,q+1,w}); } else{ read(u); int las=tl[u].size()-1; tl[u][las].r=i; } } REP(i,1,cnt)REP(j,0,tl[i].size()-1){ w=dis[tl[i][j].u]^dis[tl[i][j].v]^tl[i][j].w; insert(1,1,q+1,tl[i][j].l,tl[i][j].r,w); } divide(1,1,q+1,0); } int main(){ File(); init(); work(); return 0; }
HAOI2017 八縱八橫——線段樹分治+線性基