#41 最短路(分治+线性基)
生活随笔
收集整理的這篇文章主要介紹了
#41 最短路(分治+线性基)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
考慮異或最短路應該怎么求。那么這是個WC原題,dfs一遍找到所有有用的環丟進線性基即可,因為每一個環的權值都是可以取到且不對其他部分產生影響的。
現在給了一棵樹,不妨就把他看做原圖的dfs樹。每增加一條邊就是增加了一個環。算出權值后,現在問題變為求一個數和任選一段區間里的數的最大異或值。
比較暴力的做法是直接建線段樹,每次logn*log2v取出區間線性基。這樣可以拿50分。
線性基的合并實在太慢了。考慮能不能離線搞。每次取出跨過區間中點的詢問,處理中點左右的后綴前綴線性基,詢問時將兩邊線性基合并。于是就變成logv(logn+logv)了。
調了半天發現m和n搞反了。
果然是NOIp模擬。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<cassert> using namespace std; int read() {int x=0,f=1;char c=getchar();while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();return x*f; } #define N 300010 int n,m,q,p[N],deep[N],value[N],ans[N],t=0; struct base {int size,a[31];void ins(int x){for (register int i=30;~i;i--){if (!x) break;if (x&(1<<i))if (!a[i]) {a[i]=x;size++;break;}else x^=a[i];}}base operator +(const base&b) const{base c;if (size>b.size){c.size=size;for (int i=0;i<31;i++) c.a[i]=a[i];if (size==31) return c;for (register int i=30;~i;i--)c.ins(b.a[i]);}else{c.size=b.size;for (int i=0;i<31;i++) c.a[i]=b.a[i];if (b.size==31) return c;for (register int i=30;~i;i--)c.ins(a[i]);}return c;} }pre[N],suf[N]; struct data{int to,nxt,len; }edge[N<<1]; struct data2{int i,l,r,x; }Q[N],u[N]; void addedge(int x,int y,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].len=z,p[x]=t;} void dfs(int k,int from) {for (int i=p[k];i;i=edge[i].nxt)if (edge[i].to!=from){deep[edge[i].to]=deep[k]^edge[i].len;dfs(edge[i].to,k);} } int work(int x,base p) {for (int i=30;~i;i--)x=min(x,x^p.a[i]);return x; } void solve(int l,int r,int low,int high) {if (l>r||low>high) return;if (low==high){for (int i=l;i<=r;i++) ans[Q[i].i]=min(Q[i].x,Q[i].x^value[low]);return;}int mid=low+high>>1;for (int i=mid;i>=low;i--){if (i==mid) pre[i]=(base){0,{0}};else pre[i]=pre[i+1];pre[i].ins(value[i]);}for (int i=mid+1;i<=high;i++){if (i==mid+1) suf[i]=(base){0,{0}};else suf[i]=suf[i-1];suf[i].ins(value[i]);}int head=l-1,tail=r+1;for (int i=l;i<=r;i++)if (Q[i].l<=mid&&Q[i].r>mid) ans[Q[i].i]=work(Q[i].x,pre[Q[i].l]+suf[Q[i].r]);else if (Q[i].r<=mid) u[++head]=Q[i];else u[--tail]=Q[i];for (int i=l;i<=r;i++) Q[i]=u[i];solve(l,head,low,mid);solve(tail,r,mid+1,high); } int main() { #ifndef ONLINE_JUDGEfreopen("c.in","r",stdin);freopen("c.out","w",stdout);const char LL[]="%I64d\n"; #elseconst char LL[]="%lld\n"; #endifn=read(),m=read(),q=read();for (int i=1;i<n;i++){int x=read(),y=read(),z=read();addedge(x,y,z),addedge(y,x,z);}dfs(1,1);for (int i=1;i<=m;i++){int x=read(),y=read(),z=read();value[i]=deep[x]^deep[y]^z;}for (int i=1;i<=q;i++){int s=read(),t=read(),l=read(),r=read();Q[i].i=i,Q[i].x=deep[s]^deep[t],Q[i].l=l,Q[i].r=r;}solve(1,q,1,m);for (int i=1;i<=q;i++) printf("%d\n",ans[i]);return 0; }?
轉載于:https://www.cnblogs.com/Gloid/p/9658421.html
總結
以上是生活随笔為你收集整理的#41 最短路(分治+线性基)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 即使会溢出,也能得到正确的结果
- 下一篇: java冒泡排序,选择排序,插入排序,希