把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

BZOJ #2322. [BeiJing2011]梦想封印

题面传送门
没想到线性基还有很多优越的性质。
首先这个题一看就很线性基。我们考虑沿用[WC2011]最大XOR和路径的套路,将路径的权值种类转化为一条链与若干个任意环的异或。其中环可以用线性基维护。
看到删边不难想到倒序加边,先对边的删除时间跑出一颗最大生成树,然后每条非树边加入只需要找到在这棵生成树上的环即可,如果联通放到线性基里面去。然后路径也可以用这颗最大生成树中1号节点到所有点的路径权值的异或和。
然后现在问题变成:给你一个线性基和一个集合,每次往线性基或集合中加入一个数,每次加入后查询线性基中取若干个数,集合中取一个数异或出的数的不同种类个数。
不难发现线性基有一个性质:如果两个数\(x,y\)在线性基中异或出的最大数相同,那么这两个数产生的数是相同的,也就是说这两个数至少可以舍去一个。那么我们可以维护每个数在线性基中的最大值,然后用map维护不同的有几个即可。
但是有一个问题:线性基会加入一个数,集合中每个数对应的最大权值会改变。但是没关系,因为线性基中加入的数的个数是\(O(\log W)\)的,所以暴力对每个数去重新查询即可。
时间复杂度\(O(n\log ^2W)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define ll long long
#define db double
#define lb long db
#define N (20000+5)
#define M ((N<<2)+5)
#define K (350)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define ull unsigned ll
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((k+1)*(x)+(y))
#define R(n) (1ll*rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,m,k,Fl[N],X[N],d[N],fa[N],Fs[N];ll W[N],Ans[N];
struct Edge{int x,y,id;ll w;int t;}Q[N];I bool C1(Edge x,Edge y){return x.t>y.t;}I bool C2(Edge x,Edge y){return x.id<y.id;}
struct Ques{int to;ll w;};vector<Ques> S[N];I int GF(int x){return fa[x]^x?fa[x]=GF(fa[x]):x;}vector<int> G[N];
namespace BB{
	ll F[100],P[N];int cnt,Ph,Sh;map<ll,int>G;I ll Find(ll x){for(int i=62;~i;i--) if((x^F[i])>x) x^=F[i];return x;}
	I void BD(){G.clear();Sh=0;ll Ns;for(int i=1;i<=Ph;i++) Ns=Find(P[i]),!G.count(Ns)&&(Sh++,G[Ns]=1);}
	I void Ins(ll x){for(int i=62;~i;i--){if(!(x>>i&1)) continue;if(!F[i]){F[i]=x;cnt++;BD();break;}x^=F[i];}}
	I void CK(ll x){P[++Ph]=x;ll Ns=Find(x);!G.count(Ns)&&(G[Ns]=1,Sh++);}
}vector<ll> Wait[N];
I void Make(int x,int La){d[x]=d[La]+1;for(Ques d:S[x]) d.to^La&&(W[d.to]=W[x]^d.w,Make(d.to,x),0);} 
I void dfs(int x){for(ll d:Wait[x]) BB::Ins(d);Fs[x]=1;BB::CK(W[x]);for(int i:G[x]) dfs(i);}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	int i,j;scanf("%d%d%d",&n,&m,&k);for(i=1;i<=m;i++) scanf("%d%d%lld",&Q[i].x,&Q[i].y,&Q[i].w),Q[i].t=k+1,Q[i].id=i;for(i=1;i<=k;i++) scanf("%d",&X[i]),Q[X[i]].t=i;
	sort(Q+1,Q+m+1,C1);for(i=1;i<=n;i++) fa[i]=i;for(i=1;i<=m;i++) GF(Q[i].x)^GF(Q[i].y)&&(S[Q[i].x].PB((Ques){Q[i].y,Q[i].w}),S[Q[i].y].PB((Ques){Q[i].x,Q[i].w}),fa[GF(Q[i].x)]=GF(Q[i].y),Fl[Q[i].id]=1);
	Make(1,0);sort(Q+1,Q+m+1,C2);BB::CK(0);Fs[1]=1;for(i=1;i<=m;i++) Q[i].t==k+1&&d[Q[i].x]&&(Fl[i]?(d[Q[i].x]>d[Q[i].y]?(Fs[Q[i].y]&&(dfs(Q[i].x),0),G[Q[i].y].PB(Q[i].x)):(Fs[Q[i].x]&&(dfs(Q[i].y),0),G[Q[i].x].PB(Q[i].y))):(Fs[Q[i].x]?BB::Ins(W[Q[i].x]^W[Q[i].y]^Q[i].w):Wait[Q[i].x].PB(W[Q[i].x]^W[Q[i].y]^Q[i].w)),0);
	Ans[k]=(1ll<<BB::cnt)*BB::Sh-1;for(i=k;i;i--) d[Q[X[i]].x]&&(Fl[X[i]]?(d[Q[X[i]].x]>d[Q[X[i]].y]?(Fs[Q[X[i]].y]&&(dfs(Q[X[i]].x),0),G[Q[X[i]].y].PB(Q[X[i]].x)):(Fs[Q[X[i]].x]&&(dfs(Q[X[i]].y),0),G[Q[X[i]].x].PB(Q[X[i]].y))):(Fs[Q[X[i]].x]?BB::Ins(W[Q[X[i]].x]^W[Q[X[i]].y]^Q[X[i]].w):Wait[Q[X[i]].x].PB(W[Q[X[i]].x]^W[Q[X[i]].y]^Q[X[i]].w)),0),Ans[i-1]=(1ll<<BB::cnt)*BB::Sh-1;
	for(i=0;i<=k;i++) printf("%lld\n",Ans[i]);
}
posted @ 2022-07-06 21:37  275307894a  阅读(70)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end