T184176-「EZEC-10」序列【Trie】
阿新 • • 發佈:2021-07-11
正題
題目連結:https://www.luogu.com.cn/problem/T184176
題目大意
求有多少個長度為\(n\)的序列\(a\)滿足,都在\([0,k]\)的範圍內且滿足\(m\)個限制刑如:\(a_x\ xor\ a_y=z\)
\(0\leq n,m\leq 5\times 10^5,0\leq k<2^{30}\)
解題思路
首先假設有合法方案,那麼對於一個位置\(a_x\)確定之後與它直接或間接限制的\(a_y\)都將被確定。
我們可以設限制為一條邊,然後先\(dfs\)判斷一次是否限制之間沒有衝突。
然後考慮對於每個聯通塊我們隨意找到一個位置\(x\),那麼其他的點都將被表達為\(a_x\ xor\ w\)
然後我們要求找到有多少個\(a_x\)滿足對於所有的\(w\)都有\(a_x\ xor\ w\leq k\)。
這個可以用\(Trie\)數來做,每次封閉的是一個子樹,直接處理就好了。
時間複雜度\(O(n\log k)\)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<stack> #define ll long long using namespace std; const ll N=5e5+10,P=1e9+7; struct node{ ll to,next,w; }a[N<<1]; ll n,m,k,tot,ls[N],z[N]; ll cnt,t[N][2],res,ans=1; bool v[N];stack<ll > s; void addl(ll x,ll y,ll w){ a[++tot].to=y; a[tot].next=ls[x]; ls[x]=tot;a[tot].w=w; return; } bool dfs(ll x){ v[x]=1;s.push(z[x]); for(ll i=ls[x];i;i=a[i].next){ ll y=a[i].to; if(v[y]){ if((z[x]^a[i].w)!=z[y]) return 1; } else{ z[y]=z[x]^a[i].w; if(dfs(y))return 1; } } return 0; } void Limit(ll &x,ll w,ll p){ if(x==-1||p<0)return; if(!x){x=++cnt;t[x][0]=t[x][1]=0;} if((k>>p)&1)Limit(t[x][(w>>p)&1^1],w,p-1); else{ t[x][(w>>p)&1^1]=-1; Limit(t[x][(w>>p)&1],w,p-1); } return; } void Count(ll x,ll L,ll R){ if(L>k)return; if(x==-1)res-=min(R,k)-L+1; if(x<=0)return; ll mid=(L+R)>>1; Count(t[x][0],L,mid); Count(t[x][1],mid+1,R); return; } signed main() { scanf("%lld%lld%lld",&n,&m,&k); for(ll i=1;i<=m;i++){ ll x,y,w; scanf("%lld%lld%lld",&x,&y,&w); addl(x,y,w);addl(y,x,w); } res=0; for(ll i=1;i<=n;i++){ if(v[i])continue;cnt=t[0][0]=0; if(dfs(i))return puts("0")&0; while(!s.empty())Limit(t[0][0],s.top(),29),s.pop(); res=k+1;Count(1,0,(1<<30)-1); ans=ans*res%P; } printf("%lld\n",ans); return 0; }